lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nightowl...@apache.org
Subject [16/26] lucenenet git commit: Added missing Spatial classes, ported Spatial tests, and fixed several bugs
Date Fri, 25 Nov 2016 11:07:21 GMT
Added missing Spatial classes, ported Spatial tests, and fixed several bugs


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

Branch: refs/heads/master
Commit: d8c73530744a7b540258169f70cd893871e65ffb
Parents: bd9e92d
Author: Shad Storhaug <shad@shadstorhaug.com>
Authored: Wed Nov 16 14:42:10 2016 +0700
Committer: Shad Storhaug <shad@shadstorhaug.com>
Committed: Wed Nov 16 14:42:10 2016 +0700

----------------------------------------------------------------------
 Lucene.Net.sln                                  |    26 +
 src/Lucene.Net.Spatial/DisjointSpatialFilter.cs |     2 +-
 .../Lucene.Net.Spatial.csproj                   |     2 +
 .../Prefix/AbstractVisitingPrefixTreeFilter.cs  |   196 +-
 .../Prefix/ContainsPrefixTreeFilter.cs          |     5 +-
 .../Prefix/PrefixTreeStrategy.cs                |     4 +-
 src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs      |    44 +-
 .../Prefix/Tree/GeohashPrefixTree.cs            |    19 +-
 .../Prefix/Tree/QuadPrefixTree.cs               |    50 +-
 .../Prefix/Tree/SpatialPrefixTree.cs            |    16 +-
 .../Prefix/Tree/SpatialPrefixTreeFactory.cs     |     8 +-
 .../Serialized/SerializedDVStrategy.cs          |   409 +-
 .../Util/DistanceToShapeValueSource.cs          |   151 +
 .../Util/ShapePredicateValueSource.cs           |   146 +
 .../Vector/PointVectorStrategy.cs               |     2 +-
 .../JavaCompatibility/LuceneTestCase.cs         |   104 +
 .../JavaCompatibility/SystemTypesHelpers.cs     |    27 +-
 .../DistanceStrategyTest.cs                     |   155 +
 .../Lucene.Net.Tests.Spatial.csproj             |   130 +
 src/Lucene.Net.Tests.Spatial/PortedSolr3Test.cs |   201 +
 .../Prefix/NtsPolygonTest.cs                    |   118 +
 .../Prefix/SpatialOpRecursivePrefixTreeTest.cs  |   485 +
 .../Prefix/TestRecursivePrefixTreeStrategy.cs   |   127 +
 .../Prefix/TestTermQueryPrefixGridStrategy.cs   |    60 +
 .../Prefix/Tree/SpatialPrefixTreeTest.cs        |   105 +
 .../Properties/AssemblyInfo.cs                  |    36 +
 .../Query/SpatialArgsParserTest.cs              |    69 +
 .../QueryEqualsHashCodeTest.cs                  |   169 +
 .../Serialized/SerializedStrategyTest.cs        |    73 +
 src/Lucene.Net.Tests.Spatial/SpatialArgsTest.cs |    52 +
 src/Lucene.Net.Tests.Spatial/SpatialExample.cs  |   196 +
 .../SpatialMatchConcern.cs                      |    35 +
 src/Lucene.Net.Tests.Spatial/SpatialTestCase.cs |   248 +
 src/Lucene.Net.Tests.Spatial/SpatialTestData.cs |    78 +
 .../SpatialTestQuery.cs                         |   102 +
 .../StrategyTestCase.cs                         |   274 +
 .../Test-Files/Data/LUCENE-4464.txt             |     3 +
 .../Test-Files/Data/countries-bbox.txt          |   249 +
 .../Test-Files/Data/countries-poly.txt          |   249 +
 .../Test-Files/Data/geonames-IE.txt             | 22929 +++++++++++++++++
 .../Test-Files/Data/simple-bbox.txt             |     5 +
 .../Test-Files/Data/states-bbox.txt             |    52 +
 .../Test-Files/Data/states-poly.txt             |    52 +
 .../Test-Files/Data/world-cities-points.txt     |  2680 ++
 .../Test-Files/cities-Intersects-BBox.txt       |     3 +
 .../Test-Files/simple-Queries-BBox.txt          |     8 +
 .../Test-Files/states-Intersects-BBox.txt       |     3 +
 .../Test-Files/states-IsWithin-BBox.txt         |     4 +
 .../TestTestFramework.cs                        |    63 +
 .../Vector/TestPointVectorStrategy.cs           |    61 +
 src/Lucene.Net.Tests.Spatial/packages.config    |     4 +
 51 files changed, 30132 insertions(+), 157 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/Lucene.Net.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.sln b/Lucene.Net.sln
index 136a3fe..e7a3ef8 100644
--- a/Lucene.Net.sln
+++ b/Lucene.Net.sln
@@ -72,6 +72,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Grouping",
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Spatial", "src\Lucene.Net.Spatial\Lucene.Net.Spatial.csproj", "{35C347F4-24B2-4BE5-8117-A0E3001551CE}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Spatial", "src\Lucene.Net.Tests.Spatial\Lucene.Net.Tests.Spatial.csproj", "{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -711,6 +713,30 @@ Global
 		{35C347F4-24B2-4BE5-8117-A0E3001551CE}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
 		{35C347F4-24B2-4BE5-8117-A0E3001551CE}.Release35|x86.ActiveCfg = Release|Any CPU
 		{35C347F4-24B2-4BE5-8117-A0E3001551CE}.Release35|x86.Build.0 = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug|x86.Build.0 = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug35|x86.ActiveCfg = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Debug35|x86.Build.0 = Debug|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release|x86.ActiveCfg = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release|x86.Build.0 = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release35|Any CPU.Build.0 = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release35|x86.ActiveCfg = Release|Any CPU
+		{31F52F5C-A08F-4363-8003-23D6F7D6EB3A}.Release35|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/DisjointSpatialFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/DisjointSpatialFilter.cs b/src/Lucene.Net.Spatial/DisjointSpatialFilter.cs
index e36a97b..41842af 100644
--- a/src/Lucene.Net.Spatial/DisjointSpatialFilter.cs
+++ b/src/Lucene.Net.Spatial/DisjointSpatialFilter.cs
@@ -125,7 +125,7 @@ namespace Lucene.Net.Spatial
             }
             
             //not so much a chain but a way to conveniently invert the Filter
-            DocIdSet docIdSet = new ChainedFilter(new[] { intersectsFilter }, ChainedFilter.ANDNOT).GetDocIdSet(context, acceptDocs);
+            DocIdSet docIdSet = new ChainedFilter(new Filter[] { intersectsFilter }, ChainedFilter.ANDNOT).GetDocIdSet(context, acceptDocs);
             return BitsFilteredDocIdSet.Wrap(docIdSet, docsWithField);
         }
     }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Lucene.Net.Spatial.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Lucene.Net.Spatial.csproj b/src/Lucene.Net.Spatial/Lucene.Net.Spatial.csproj
index 2689008..28c3e51 100644
--- a/src/Lucene.Net.Spatial/Lucene.Net.Spatial.csproj
+++ b/src/Lucene.Net.Spatial/Lucene.Net.Spatial.csproj
@@ -100,10 +100,12 @@
     <Compile Include="Query\UnsupportedSpatialOperation.cs" />
     <Compile Include="Serialized\SerializedDVStrategy.cs" />
     <Compile Include="SpatialStrategy.cs" />
+    <Compile Include="Util\DistanceToShapeValueSource.cs" />
     <Compile Include="Util\ShapeFieldCacheDistanceValueSource.cs" />
     <Compile Include="Util\CachingDoubleValueSource.cs" />
     <Compile Include="Util\ShapeFieldCache.cs" />
     <Compile Include="Util\ShapeFieldCacheProvider.cs" />
+    <Compile Include="Util\ShapePredicateValueSource.cs" />
     <Compile Include="Util\ValueSourceFilter.cs" />
     <Compile Include="Vector\DistanceValueSource.cs" />
     <Compile Include="Vector\PointVectorStrategy.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Prefix/AbstractVisitingPrefixTreeFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/AbstractVisitingPrefixTreeFilter.cs b/src/Lucene.Net.Spatial/Prefix/AbstractVisitingPrefixTreeFilter.cs
index e368a55..3118351 100644
--- a/src/Lucene.Net.Spatial/Prefix/AbstractVisitingPrefixTreeFilter.cs
+++ b/src/Lucene.Net.Spatial/Prefix/AbstractVisitingPrefixTreeFilter.cs
@@ -160,14 +160,15 @@ namespace Lucene.Net.Spatial.Prefix
         public abstract class VisitorTemplate : BaseTermsEnumTraverser
         {
             private readonly AbstractVisitingPrefixTreeFilter outerInstance;
-            private readonly BytesRef curVNodeTerm = new BytesRef();
+
             protected internal readonly bool hasIndexedLeaves;//if false then we can skip looking for them
 
             private VNode curVNode;//current pointer, derived from query shape
+            private BytesRef curVNodeTerm = new BytesRef();//curVNode.cell's term.
+            private Cell scanCell;
+
             private BytesRef thisTerm; //the result of termsEnum.term()
-            private Cell scanCell;//curVNode.cell's term.
 
-            /// <exception cref="System.IO.IOException"></exception>
             public VisitorTemplate(AbstractVisitingPrefixTreeFilter outerInstance, AtomicReaderContext context, Bits acceptDocs,
                                    bool hasIndexedLeaves)
                 : base(outerInstance, context, acceptDocs)
@@ -176,7 +177,6 @@ namespace Lucene.Net.Spatial.Prefix
                 this.hasIndexedLeaves = hasIndexedLeaves;
             }
 
-            /// <exception cref="System.IO.IOException"></exception>
             public virtual DocIdSet GetDocIdSet()
             {
                 Debug.Assert(curVNode == null, "Called more than once?");
@@ -192,18 +192,29 @@ namespace Lucene.Net.Spatial.Prefix
                 // all done
                 curVNode = new VNode(null);
                 curVNode.Reset(outerInstance.grid.WorldCell);
+
                 Start();
+
                 AddIntersectingChildren();
-                while (thisTerm != null)
+
+                while (thisTerm != null)//terminates for other reasons too!
                 {
-                    //terminates for other reasons too!
                     //Advance curVNode pointer
                     if (curVNode.children != null)
                     {
                         //-- HAVE CHILDREN: DESCEND
-                        Debug.Assert(curVNode.children.MoveNext());
+
+                        // LUCENENET NOTE: Must call this line before calling MoveNext()
+                        // on the enumerator.
+
                         //if we put it there then it has something
                         PreSiblings(curVNode);
+
+                        // LUCENENET IMPORTANT: Must not call this inline with Debug.Assert
+                        // because the compiler removes Debug.Assert statements in release mode!!
+                        bool hasNext = curVNode.children.MoveNext();
+                        Debug.Assert(hasNext);
+
                         curVNode = curVNode.children.Current;
                     }
                     else
@@ -236,12 +247,11 @@ namespace Lucene.Net.Spatial.Prefix
                     //Seek to curVNode's cell (or skip if termsEnum has moved beyond)
                     curVNodeTerm.Bytes = curVNode.cell.GetTokenBytes();
                     curVNodeTerm.Length = curVNodeTerm.Bytes.Length;
-                    int compare = termsEnum.Comparator.Compare(thisTerm, curVNodeTerm
-                        );
+                    int compare = termsEnum.Comparator.Compare(thisTerm, curVNodeTerm);
                     if (compare > 0)
                     {
                         // leap frog (termsEnum is beyond where we would otherwise seek)
-                        Debug.Assert(!((AtomicReader)context.Reader).Terms(outerInstance.fieldName).Iterator(null).SeekExact(curVNodeTerm), "should be absent");
+                        Debug.Assert(!context.AtomicReader.Terms(outerInstance.fieldName).Iterator(null).SeekExact(curVNodeTerm), "should be absent");
                     }
                     else
                     {
@@ -257,10 +267,9 @@ namespace Lucene.Net.Spatial.Prefix
                             thisTerm = termsEnum.Term();
                             if (seekStatus == TermsEnum.SeekStatus.NOT_FOUND)
                             {
-                                continue;
+                                continue; // leap frog
                             }
                         }
-                        // leap frog
                         // Visit!
                         bool descend = Visit(curVNode.cell);
                         //advance
@@ -302,10 +311,8 @@ namespace Lucene.Net.Spatial.Prefix
                 {
                     //If the next indexed term just adds a leaf marker ('+') to cell,
                     // then add all of those docs
-                    Debug.Assert(StringHelper.StartsWith(thisTerm, curVNodeTerm
-                                     ));
-                    scanCell = outerInstance.grid.GetCell(thisTerm.Bytes, thisTerm.Offset
-                                                       , thisTerm.Length, scanCell);
+                    Debug.Assert(StringHelper.StartsWith(thisTerm, curVNodeTerm));//TODO refactor to use method on curVNode.cell
+                    scanCell = outerInstance.grid.GetCell(thisTerm.Bytes, thisTerm.Offset, thisTerm.Length, scanCell);
                     if (scanCell.Level == cell.Level && scanCell.IsLeaf())
                     {
                         VisitLeaf(scanCell);
@@ -373,73 +380,23 @@ namespace Lucene.Net.Spatial.Prefix
             protected internal virtual void Scan(int scanDetailLevel)
             {
                 for (;
-                    thisTerm != null && StringHelper.StartsWith(thisTerm, curVNodeTerm
-                                            );
+                    thisTerm != null && StringHelper.StartsWith(thisTerm, curVNodeTerm);//TODO refactor to use method on curVNode.cell
                     thisTerm = termsEnum.Next())
                 {
-                    scanCell = outerInstance.grid.GetCell(thisTerm.Bytes, thisTerm.Offset
-                                                       , thisTerm.Length, scanCell);
+                    scanCell = outerInstance.grid.GetCell(thisTerm.Bytes, thisTerm.Offset, thisTerm.Length, scanCell);
+
                     int termLevel = scanCell.Level;
-                    if (termLevel > scanDetailLevel)
+                    if (termLevel < scanDetailLevel)
                     {
-                        continue;
+                        if (scanCell.IsLeaf())
+                            VisitScanned(scanCell);
                     }
-                    if (termLevel == scanDetailLevel || scanCell.IsLeaf())
+                    else if (termLevel == scanDetailLevel)
                     {
-                        VisitScanned(scanCell);
+                        if (!scanCell.IsLeaf())//LUCENE-5529
+                            VisitScanned(scanCell);
                     }
-                }
-            }
-
-            /// <summary>Called first to setup things.</summary>
-            /// <remarks>Called first to setup things.</remarks>
-            /// <exception cref="System.IO.IOException"></exception>
-            protected internal abstract void Start();
-
-            /// <summary>Called last to return the result.</summary>
-            /// <remarks>Called last to return the result.</remarks>
-            /// <exception cref="System.IO.IOException"></exception>
-            protected internal abstract DocIdSet Finish();
-
-            /// <summary>
-            /// Visit an indexed cell returned from
-            /// <see cref="FindSubCellsToVisit(Lucene.Net.Spatial.Prefix.Tree.Cell)">FindSubCellsToVisit(Lucene.Net.Spatial.Prefix.Tree.Cell)
-            /// 	</see>
-            /// .
-            /// </summary>
-            /// <param name="cell">An intersecting cell.</param>
-            /// <returns>
-            /// true to descend to more levels. It is an error to return true
-            /// if cell.level == detailLevel
-            /// </returns>
-            /// <exception cref="System.IO.IOException"></exception>
-            protected internal abstract bool Visit(Cell cell);
-
-            /// <summary>Called after visit() returns true and an indexed leaf cell is found.</summary>
-            /// <remarks>
-            /// Called after visit() returns true and an indexed leaf cell is found. An
-            /// indexed leaf cell means associated documents generally won't be found at
-            /// further detail levels.
-            /// </remarks>
-            /// <exception cref="System.IO.IOException"></exception>
-            protected internal abstract void VisitLeaf(Cell cell);
-
-            /// <summary>The cell is either indexed as a leaf or is the last level of detail.</summary>
-            /// <remarks>
-            /// The cell is either indexed as a leaf or is the last level of detail. It
-            /// might not even intersect the query shape, so be sure to check for that.
-            /// </remarks>
-            /// <exception cref="System.IO.IOException"></exception>
-            protected internal abstract void VisitScanned(Cell cell);
-
-            /// <exception cref="System.IO.IOException"></exception>
-            protected internal virtual void PreSiblings(VNode vNode)
-            {
-            }
-
-            /// <exception cref="System.IO.IOException"></exception>
-            protected internal virtual void PostSiblings(VNode vNode)
-            {
+                }//term loop
             }
 
             #region Nested type: VNodeCellIterator
@@ -451,14 +408,15 @@ namespace Lucene.Net.Spatial.Prefix
             /// </summary>
             private class VNodeCellIterator : IEnumerator<VNode>
             {
-                private readonly VisitorTemplate _enclosing;
+                private readonly VisitorTemplate outerInstance;
                 internal readonly IEnumerator<Cell> cellIter;
 
                 private readonly VNode vNode;
+                private bool first = true;
 
-                internal VNodeCellIterator(VisitorTemplate _enclosing, IEnumerator<Cell> cellIter, VNode vNode)
+                internal VNodeCellIterator(VisitorTemplate outerInstance, IEnumerator<Cell> cellIter, VNode vNode)
                 {
-                    this._enclosing = _enclosing;
+                    this.outerInstance = outerInstance;
                     //term loop
                     this.cellIter = cellIter;
                     this.vNode = vNode;
@@ -475,7 +433,31 @@ namespace Lucene.Net.Spatial.Prefix
 
                 public bool MoveNext()
                 {
-                    return cellIter.MoveNext();
+                    //Debug.Assert(cellIter.Current != null);
+
+                    // LUCENENET NOTE: The consumer of this class calls
+                    // cellIter.MoveNext() before it is instantiated.
+                    // So, the first call here
+                    // to MoveNext() must not move the cursor.
+                    bool result;
+                    if (!first)
+                    {
+                        result = cellIter.MoveNext();
+                    }
+                    else
+                    {
+                        result = true;
+                        first = false;
+                    }
+
+                    // LUCENENET NOTE: Need to skip this call
+                    // if there are no more results because null
+                    // is not allowed
+                    if (result == true)
+                    {
+                        vNode.Reset(cellIter.Current);
+                    }
+                    return result;
                 }
 
                 public void Reset()
@@ -487,8 +469,8 @@ namespace Lucene.Net.Spatial.Prefix
                 {
                     get
                     {
-                        Debug.Assert(cellIter.Current != null);
-                        vNode.Reset(cellIter.Current);
+                        //Debug.Assert(cellIter.Current != null);
+                        //vNode.Reset(cellIter.Current);
                         return vNode;
                     }
                 }
@@ -503,6 +485,56 @@ namespace Lucene.Net.Spatial.Prefix
 
             #endregion
 
+            /// <summary>Called first to setup things.</summary>
+            /// <remarks>Called first to setup things.</remarks>
+            /// <exception cref="System.IO.IOException"></exception>
+            protected internal abstract void Start();
+
+            /// <summary>Called last to return the result.</summary>
+            /// <remarks>Called last to return the result.</remarks>
+            /// <exception cref="System.IO.IOException"></exception>
+            protected internal abstract DocIdSet Finish();
+
+            /// <summary>
+            /// Visit an indexed cell returned from
+            /// <see cref="FindSubCellsToVisit(Lucene.Net.Spatial.Prefix.Tree.Cell)">FindSubCellsToVisit(Lucene.Net.Spatial.Prefix.Tree.Cell)
+            /// 	</see>
+            /// .
+            /// </summary>
+            /// <param name="cell">An intersecting cell.</param>
+            /// <returns>
+            /// true to descend to more levels. It is an error to return true
+            /// if cell.level == detailLevel
+            /// </returns>
+            /// <exception cref="System.IO.IOException"></exception>
+            protected internal abstract bool Visit(Cell cell);
+
+            /// <summary>Called after visit() returns true and an indexed leaf cell is found.</summary>
+            /// <remarks>
+            /// Called after visit() returns true and an indexed leaf cell is found. An
+            /// indexed leaf cell means associated documents generally won't be found at
+            /// further detail levels.
+            /// </remarks>
+            /// <exception cref="System.IO.IOException"></exception>
+            protected internal abstract void VisitLeaf(Cell cell);
+
+            /// <summary>The cell is either indexed as a leaf or is the last level of detail.</summary>
+            /// <remarks>
+            /// The cell is either indexed as a leaf or is the last level of detail. It
+            /// might not even intersect the query shape, so be sure to check for that.
+            /// </remarks>
+            /// <exception cref="System.IO.IOException"></exception>
+            protected internal abstract void VisitScanned(Cell cell);
+
+            /// <exception cref="System.IO.IOException"></exception>
+            protected internal virtual void PreSiblings(VNode vNode)
+            {
+            }
+
+            /// <exception cref="System.IO.IOException"></exception>
+            protected internal virtual void PostSiblings(VNode vNode)
+            {
+            }
             //class VisitorTemplate
         }
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Prefix/ContainsPrefixTreeFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/ContainsPrefixTreeFilter.cs b/src/Lucene.Net.Spatial/Prefix/ContainsPrefixTreeFilter.cs
index 76a95b8..ca0eb3d 100644
--- a/src/Lucene.Net.Spatial/Prefix/ContainsPrefixTreeFilter.cs
+++ b/src/Lucene.Net.Spatial/Prefix/ContainsPrefixTreeFilter.cs
@@ -24,6 +24,7 @@ using Lucene.Net.Spatial.Prefix;
 using Lucene.Net.Spatial.Prefix.Tree;
 using Lucene.Net.Spatial.Queries;
 using Lucene.Net.Util;
+using System.Diagnostics;
 
 namespace Lucene.Net.Spatial.Prefix
 {
@@ -157,8 +158,8 @@ namespace Lucene.Net.Spatial.Prefix
             /// <exception cref="System.IO.IOException"></exception>
             private SmallDocSet GetLeafDocs(Cell leafCell, Bits acceptContains)
             {
-                System.Diagnostics.Debug.Assert(new BytesRef(leafCell.GetTokenBytes()).Equals(termBytes));
-                System.Diagnostics.Debug.Assert(leafCell.Equals(lastLeaf));//don't call for same leaf again
+                Debug.Assert(new BytesRef(leafCell.GetTokenBytes()).Equals(termBytes));
+                Debug.Assert(leafCell.Equals(lastLeaf));//don't call for same leaf again
                 lastLeaf = leafCell;
 
                 if (termsEnum == null)

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/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
index 4a21ebc..ea36656 100644
--- a/src/Lucene.Net.Spatial/Prefix/PrefixTreeStrategy.cs
+++ b/src/Lucene.Net.Spatial/Prefix/PrefixTreeStrategy.cs
@@ -181,14 +181,14 @@ namespace Lucene.Net.Spatial.Prefix
         /// 	</remarks>
         internal sealed class CellTokenStream : TokenStream
         {
-            private readonly CharTermAttribute termAtt;
+            private readonly ICharTermAttribute termAtt;
 
             private IEnumerator<Cell> iter = null;
 
             public CellTokenStream(IEnumerator<Cell> tokens)
             {
                 this.iter = tokens;
-                termAtt = AddAttribute<CharTermAttribute>();
+                termAtt = AddAttribute<ICharTermAttribute>();
             }
 
             internal string nextTokenStringNeedingLeaf;

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs b/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs
index f160688..8af4cd8 100644
--- a/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs
+++ b/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs
@@ -22,6 +22,7 @@ using System.Text;
 using Lucene.Net.Spatial.Util;
 using Lucene.Net.Util;
 using Spatial4n.Core.Shapes;
+using Spatial4n.Core.Context;
 
 namespace Lucene.Net.Spatial.Prefix.Tree
 {
@@ -33,6 +34,16 @@ namespace Lucene.Net.Spatial.Prefix.Tree
     /// <lucene.experimental></lucene.experimental>
     public abstract class Cell : IComparable<Cell>
     {
+        /// <summary>
+        /// LUCENENET specific - we need to set the SpatialPrefixTree before calling overridden 
+        /// members of this class, just in case those overridden members require it. This is
+        /// not possible from the subclass because the constructor of the base class runs first.
+        /// So we need to move the reference here and also set it before running the normal constructor
+        /// logic.
+        /// </summary>
+        protected readonly SpatialPrefixTree outerInstance;
+
+
         public const byte LEAF_BYTE = (byte)('+');//NOTE: must sort before letters & numbers
 
         /*
@@ -43,13 +54,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
         private int b_off;
         private int b_len;
 
-        /// <summary>Always false for points.</summary>
-        /// <remarks>
-        /// Always false for points. Otherwise, indicate no further sub-cells are going
-        /// to be provided because shapeRel is WITHIN or maxLevels or a detailLevel is
-        /// hit.
-        /// </remarks>
-        protected internal bool leaf;
+        private string token;//this is the only part of equality
 
         /// <summary>
         /// When set via getSubCells(filter), it is the relationship between this cell
@@ -61,10 +66,20 @@ namespace Lucene.Net.Spatial.Prefix.Tree
         /// </remarks>
         protected internal SpatialRelation shapeRel = SpatialRelation.NULL_VALUE;//set in getSubCells(filter), and via setLeaf().
 
-        private string token;//this is the only part of equality
+        /// <summary>Always false for points.</summary>
+        /// <remarks>
+        /// Always false for points. Otherwise, indicate no further sub-cells are going
+        /// to be provided because shapeRel is WITHIN or maxLevels or a detailLevel is
+        /// hit.
+        /// </remarks>
+        protected internal bool leaf;
 
-        protected internal Cell(string token)
+        protected internal Cell(SpatialPrefixTree outerInstance, string token)
         {
+            // LUCENENET specific - set the outer instance here
+            // because overrides of GetShape() may require it
+            this.outerInstance = outerInstance;
+
             //NOTE: must sort before letters & numbers
             //this is the only part of equality
             this.token = token;
@@ -79,8 +94,12 @@ namespace Lucene.Net.Spatial.Prefix.Tree
             }
         }
 
-        protected internal Cell(byte[] bytes, int off, int len)
+        protected internal Cell(SpatialPrefixTree outerInstance, byte[] bytes, int off, int len)
         {
+            // LUCENENET specific - set the outer instance here
+            // because overrides of GetShape() may require it
+            this.outerInstance = outerInstance;
+
             //ensure any lazy instantiation completes to make this threadsafe
             this.bytes = bytes;
             b_off = off;
@@ -170,7 +189,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
             get
             {
                 if (token == null)
-                    throw new InvalidOperationException("Somehow we got a null token");
+                    token = Encoding.UTF8.GetString(bytes, b_off, b_len);
                 return token;
             }
         }
@@ -203,8 +222,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
         {
             get
             {
-                return token.Length;
-                //return token != null ? token.Length : b_len;
+                return token != null ? token.Length : b_len;
             }
         }
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Prefix/Tree/GeohashPrefixTree.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/Tree/GeohashPrefixTree.cs b/src/Lucene.Net.Spatial/Prefix/Tree/GeohashPrefixTree.cs
index 4ad1fdb..2218ca0 100644
--- a/src/Lucene.Net.Spatial/Prefix/Tree/GeohashPrefixTree.cs
+++ b/src/Lucene.Net.Spatial/Prefix/Tree/GeohashPrefixTree.cs
@@ -115,19 +115,16 @@ namespace Lucene.Net.Spatial.Prefix.Tree
 
         internal class GhCell : Cell
         {
-            private readonly GeohashPrefixTree _enclosing;
             private IShape shape;
 
-            internal GhCell(GeohashPrefixTree _enclosing, string token)
-                : base(token)
+            internal GhCell(GeohashPrefixTree outerInstance, string token)
+                : base(outerInstance, token)
             {
-                this._enclosing = _enclosing;
             }
 
-            internal GhCell(GeohashPrefixTree _enclosing, byte[] bytes, int off, int len)
-                : base(bytes, off, len)
+            internal GhCell(GeohashPrefixTree outerInstance, byte[] bytes, int off, int len)
+                : base(outerInstance, bytes, off, len)
             {
-                this._enclosing = _enclosing;
             }
 
             public override void Reset(byte[] bytes, int off, int len)
@@ -143,7 +140,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
                 IList<Cell> cells = new List<Cell>(hashes.Length);
                 foreach (string hash in hashes)
                 {
-                    cells.Add(new GhCell(_enclosing, hash));
+                    cells.Add(new GhCell((GeohashPrefixTree)outerInstance, hash));
                 }
                 return cells;
             }
@@ -156,7 +153,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
             //8x4
             public override Cell GetSubCell(IPoint p)
             {
-                return _enclosing.GetCell(p, Level + 1);
+                return outerInstance.GetCell(p, Level + 1);
             }
 
             //not performant!
@@ -165,14 +162,14 @@ namespace Lucene.Net.Spatial.Prefix.Tree
             {
                 if (shape == null)
                 {
-                    shape = GeohashUtils.DecodeBoundary(Geohash, _enclosing.ctx);
+                    shape = GeohashUtils.DecodeBoundary(Geohash, outerInstance.ctx);
                 }
                 return shape;
             }
 
             public override IPoint GetCenter()
             {
-                return GeohashUtils.Decode(Geohash, _enclosing.ctx);
+                return GeohashUtils.Decode(Geohash, outerInstance.ctx);
             }
 
             private string Geohash

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Prefix/Tree/QuadPrefixTree.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/Tree/QuadPrefixTree.cs b/src/Lucene.Net.Spatial/Prefix/Tree/QuadPrefixTree.cs
index f99f702..26763cc 100644
--- a/src/Lucene.Net.Spatial/Prefix/Tree/QuadPrefixTree.cs
+++ b/src/Lucene.Net.Spatial/Prefix/Tree/QuadPrefixTree.cs
@@ -231,27 +231,23 @@ namespace Lucene.Net.Spatial.Prefix.Tree
 
         internal class QuadCell : Cell
         {
-            private readonly QuadPrefixTree _enclosing;
             private IShape shape;
 
-            public QuadCell(QuadPrefixTree _enclosing, string token)
-                : base(token)
+            public QuadCell(QuadPrefixTree outerInstance, string token)
+                : base(outerInstance, token)
             {
-                this._enclosing = _enclosing;
             }
 
-            public QuadCell(QuadPrefixTree _enclosing, string token, SpatialRelation shapeRel
+            public QuadCell(QuadPrefixTree outerInstance, string token, SpatialRelation shapeRel
                 )
-                : base(token)
+                : base(outerInstance, token)
             {
-                this._enclosing = _enclosing;
                 this.shapeRel = shapeRel;
             }
 
-            internal QuadCell(QuadPrefixTree _enclosing, byte[] bytes, int off, int len)
-                : base(bytes, off, len)
+            internal QuadCell(QuadPrefixTree outerInstance, byte[] bytes, int off, int len)
+                : base(outerInstance, bytes, off, len)
             {
-                this._enclosing = _enclosing;
             }
 
             public override void Reset(byte[] bytes, int off, int len)
@@ -262,11 +258,12 @@ namespace Lucene.Net.Spatial.Prefix.Tree
 
             protected internal override ICollection<Cell> GetSubCells()
             {
+                QuadPrefixTree outerInstance = (QuadPrefixTree)this.outerInstance;
                 IList<Cell> cells = new List<Cell>(4);
-                cells.Add(new QuadCell(_enclosing, TokenString + "A"));
-                cells.Add(new QuadCell(_enclosing, TokenString + "B"));
-                cells.Add(new QuadCell(_enclosing, TokenString + "C"));
-                cells.Add(new QuadCell(_enclosing, TokenString + "D"));
+                cells.Add(new QuadCell(outerInstance, TokenString + "A"));
+                cells.Add(new QuadCell(outerInstance, TokenString + "B"));
+                cells.Add(new QuadCell(outerInstance, TokenString + "C"));
+                cells.Add(new QuadCell(outerInstance, TokenString + "D"));
                 return cells;
             }
 
@@ -277,7 +274,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
 
             public override Cell GetSubCell(IPoint p)
             {
-                return _enclosing.GetCell(p, Level + 1);
+                return outerInstance.GetCell(p, Level + 1);
             }
 
             //not performant!
@@ -293,22 +290,23 @@ namespace Lucene.Net.Spatial.Prefix.Tree
 
             private IRectangle MakeShape()
             {
+                QuadPrefixTree outerInstance = (QuadPrefixTree)this.outerInstance;
                 string token = TokenString;
-                double xmin = _enclosing.xmin;
-                double ymin = _enclosing.ymin;
+                double xmin = outerInstance.xmin;
+                double ymin = outerInstance.ymin;
                 for (int i = 0; i < token.Length; i++)
                 {
                     char c = token[i];
                     if ('A' == c || 'a' == c)
                     {
-                        ymin += _enclosing.levelH[i];
+                        ymin += outerInstance.levelH[i];
                     }
                     else
                     {
                         if ('B' == c || 'b' == c)
                         {
-                            xmin += _enclosing.levelW[i];
-                            ymin += _enclosing.levelH[i];
+                            xmin += outerInstance.levelW[i];
+                            ymin += outerInstance.levelH[i];
                         }
                         else
                         {
@@ -320,7 +318,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
                                 // nothing really
                                 if ('D' == c || 'd' == c)
                                 {
-                                    xmin += _enclosing.levelW[i];
+                                    xmin += outerInstance.levelW[i];
                                 }
                                 else
                                 {
@@ -335,15 +333,15 @@ namespace Lucene.Net.Spatial.Prefix.Tree
                 double height;
                 if (len > 0)
                 {
-                    width = _enclosing.levelW[len - 1];
-                    height = _enclosing.levelH[len - 1];
+                    width = outerInstance.levelW[len - 1];
+                    height = outerInstance.levelH[len - 1];
                 }
                 else
                 {
-                    width = _enclosing.gridW;
-                    height = _enclosing.gridH;
+                    width = outerInstance.gridW;
+                    height = outerInstance.gridH;
                 }
-                return _enclosing.ctx.MakeRectangle(xmin, xmin + width, ymin, ymin + height);
+                return outerInstance.ctx.MakeRectangle(xmin, xmin + width, ymin, ymin + height);
             }
 
             //QuadCell

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTree.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTree.cs b/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTree.cs
index 6d97c5c..77f61fb 100644
--- a/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTree.cs
+++ b/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTree.cs
@@ -195,8 +195,8 @@ namespace Lucene.Net.Spatial.Prefix.Tree
         /// ~20-25% fewer cells.
         /// </param>
         /// <returns>a set of cells (no dups), sorted, immutable, non-null</returns>
-        public virtual IList<Cell> GetCells(IShape shape, int detailLevel
-            , bool inclParents, bool simplify)
+        public virtual IList<Cell> GetCells(IShape shape, int detailLevel, bool inclParents, 
+            bool simplify)
         {
             //TODO consider an on-demand iterator -- it won't build up all cells in memory.
             if (detailLevel > maxLevels)
@@ -208,8 +208,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
                 return GetCells((IPoint)shape, detailLevel, inclParents);
             }
             IList<Cell> cells = new List<Cell>(inclParents ? 4096 : 2048);
-            RecursiveGetCells(WorldCell, shape, detailLevel, inclParents, simplify, cells
-                );
+            RecursiveGetCells(WorldCell, shape, detailLevel, inclParents, simplify, cells);
             return cells;
         }
 
@@ -218,8 +217,9 @@ namespace Lucene.Net.Spatial.Prefix.Tree
         /// Returns true if cell was added as a leaf. If it wasn't it recursively
         /// descends.
         /// </remarks>
-        private bool RecursiveGetCells(Cell cell, IShape shape, int
-             detailLevel, bool inclParents, bool simplify, IList<Cell> result)
+        private bool RecursiveGetCells(Cell cell, IShape shape, int detailLevel, 
+            bool inclParents, bool simplify, 
+            IList<Cell> result)
         {
             if (cell.Level == detailLevel)
             {
@@ -292,11 +292,11 @@ namespace Lucene.Net.Spatial.Prefix.Tree
 #endif
             }
             string endToken = cell.TokenString;
-            System.Diagnostics.Debug.Assert(endToken.Length == detailLevel);
+            Debug.Assert(endToken.Length == detailLevel);
             IList<Cell> cells = new List<Cell>(detailLevel);
             for (int i = 1; i < detailLevel; i++)
             {
-                cells.Add(GetCell(endToken.Substring(0, i)));
+                cells.Add(GetCell(endToken.Substring(0, i - 0)));
             }
             cells.Add(cell);
             return cells;

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTreeFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTreeFactory.cs b/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTreeFactory.cs
index a1c7011..cca47ec 100644
--- a/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTreeFactory.cs
+++ b/src/Lucene.Net.Spatial/Prefix/Tree/SpatialPrefixTreeFactory.cs
@@ -18,6 +18,7 @@ using System;
 using System.Collections.Generic;
 using Spatial4n.Core.Context;
 using Spatial4n.Core.Distance;
+using System.Globalization;
 
 namespace Lucene.Net.Spatial.Prefix.Tree
 {
@@ -74,7 +75,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
                     try
                     {
                         Type c = Type.GetType(cname);
-                        instance = (SpatialPrefixTreeFactory)System.Activator.CreateInstance(c);
+                        instance = (SpatialPrefixTreeFactory)Activator.CreateInstance(c);
                     }
                     catch (Exception e)
                     {
@@ -86,8 +87,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
             return instance.NewSPT();
         }
 
-        protected internal virtual void Init(IDictionary<string, string> args, SpatialContext
-             ctx)
+        protected internal virtual void Init(IDictionary<string, string> args, SpatialContext ctx)
         {
             this.args = args;
             this.ctx = ctx;
@@ -99,7 +99,7 @@ namespace Lucene.Net.Spatial.Prefix.Tree
             string mlStr = args[MaxLevels];
             if (mlStr != null)
             {
-                maxLevels = int.Parse(mlStr);
+                maxLevels = int.Parse(mlStr, CultureInfo.InvariantCulture);
                 return;
             }
             double degrees;

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Serialized/SerializedDVStrategy.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Serialized/SerializedDVStrategy.cs b/src/Lucene.Net.Spatial/Serialized/SerializedDVStrategy.cs
index 92e4aaf..f3413b2 100644
--- a/src/Lucene.Net.Spatial/Serialized/SerializedDVStrategy.cs
+++ b/src/Lucene.Net.Spatial/Serialized/SerializedDVStrategy.cs
@@ -30,6 +30,10 @@ using Lucene.Net.Support;
 using Lucene.Net.Util;
 using Spatial4n.Core.Context;
 using Spatial4n.Core.Shapes;
+using Lucene.Net.Index;
+using Spatial4n.Core.Io;
+using System.Collections;
+using Lucene.Net.Spatial.Util;
 
 namespace Lucene.Net.Spatial.Serialized
 {
@@ -45,25 +49,418 @@ namespace Lucene.Net.Spatial.Serialized
     /// </summary>
     public class SerializedDVStrategy : SpatialStrategy
     {
-        public SerializedDVStrategy(SpatialContext ctx, string fieldName) : base(ctx, fieldName)
+        /// <summary>
+        /// A cache heuristic for the buf size based on the last shape size.
+        /// </summary>
+        //TODO do we make this non-volatile since it's merely a heuristic?
+        private volatile int indexLastBufSize = 8 * 1024;//8KB default on first run
+
+        /// <summary>
+        /// Constructs the spatial strategy with its mandatory arguments.
+        /// </summary>
+        public SerializedDVStrategy(SpatialContext ctx, string fieldName)
+            : base(ctx, fieldName)
         {
-            throw new NotImplementedException();
         }
 
         public override Field[] CreateIndexableFields(IShape shape)
         {
-            throw new NotImplementedException();
+            int bufSize = Math.Max(128, (int)(this.indexLastBufSize * 1.5));//50% headroom over last
+            ByteArrayOutputStream byteStream = new ByteArrayOutputStream(bufSize);
+            BytesRef bytesRef = new BytesRef();//receiver of byteStream's bytes
+            try
+            {
+                ctx.BinaryCodec.WriteShape(new BinaryWriter(byteStream), shape);
+
+                //this is a hack to avoid redundant byte array copying by byteStream.toByteArray()
+                byteStream.WriteTo(new OutputStreamAnonymousHelper(bytesRef));
+
+
+                //            byteStream.WriteTo(new FilterOutputStream(null/*not used*/) {
+                //    @Override
+                //    public void write(byte[] b, int off, int len) throws IOException
+                //    {
+                //        bytesRef.bytes = b;
+                //        bytesRef.offset = off;
+                //        bytesRef.length = len;
+                //    }
+                //});
+            }
+            catch (IOException e)
+            {
+                throw new ApplicationException(e.Message, e);
+            }
+            this.indexLastBufSize = bytesRef.Length;//cache heuristic
+            return new Field[] { new BinaryDocValuesField(FieldName, bytesRef) };
+        }
+
+        internal class OutputStreamAnonymousHelper : MemoryStream
+        {
+            private readonly BytesRef bytesRef;
+
+            public OutputStreamAnonymousHelper(BytesRef bytesRef)
+            {
+                this.bytesRef = bytesRef;
+            }
+
+            public override void Write(byte[] buffer, int index, int count)
+            {
+                bytesRef.Bytes = buffer;
+                bytesRef.Offset = index;
+                bytesRef.Length = count;
+            }
         }
 
         public override ValueSource MakeDistanceValueSource(IPoint queryPoint, double multiplier)
         {
-            throw new NotImplementedException();
+            //TODO if makeShapeValueSource gets lifted to the top; this could become a generic impl.
+            return new DistanceToShapeValueSource(MakeShapeValueSource(), queryPoint, multiplier, ctx);
         }
 
+        public override ConstantScoreQuery MakeQuery(SpatialArgs args)
+        {
+            throw new NotSupportedException("This strategy can't return a query that operates" +
+                " efficiently. Instead try a Filter or ValueSource.");
+        }
+
+        /// <summary>
+        /// Returns a Filter that should be used with <see cref="FilteredQuery.QUERY_FIRST_FILTER_STRATEGY"/>.
+        /// Use in another manner is likely to result in an <see cref="NotSupportedException"/>
+        /// to prevent misuse because the filter can't efficiently work via iteration.
+        /// </summary>
         public override Filter MakeFilter(SpatialArgs args)
         {
-            throw new NotImplementedException();
+            ValueSource shapeValueSource = MakeShapeValueSource();
+            ShapePredicateValueSource predicateValueSource = new ShapePredicateValueSource(
+                shapeValueSource, args.Operation, args.Shape);
+            return new PredicateValueSourceFilter(predicateValueSource);
         }
-    }
 
+        /**
+        * Provides access to each shape per document as a ValueSource in which
+        * {@link org.apache.lucene.queries.function.FunctionValues#objectVal(int)} returns a {@link
+        * Shape}.
+        */ //TODO raise to SpatialStrategy
+        public virtual ValueSource MakeShapeValueSource()
+        {
+            return new ShapeDocValueSource(this, FieldName, ctx.BinaryCodec);
+        }
+
+        /// <summary>
+        /// This filter only supports returning a DocSet with a GetBits(). If you try to grab the
+        /// iterator then you'll get an UnsupportedOperationException.
+        /// </summary>
+        internal class PredicateValueSourceFilter : Filter
+        {
+            private readonly ValueSource predicateValueSource;//we call boolVal(doc)
+
+            public PredicateValueSourceFilter(ValueSource predicateValueSource)
+            {
+                this.predicateValueSource = predicateValueSource;
+            }
+
+            public override DocIdSet GetDocIdSet(AtomicReaderContext context, Bits acceptDocs)
+            {
+                return new DocIdSetAnonymousHelper(this, context, acceptDocs);
+
+                //      return new DocIdSet()
+                //        {
+                //            @Override
+                //        public DocIdSetIterator iterator() throws IOException
+                //        {
+                //          throw new UnsupportedOperationException(
+                //              "Iteration is too slow; instead try FilteredQuery.QUERY_FIRST_FILTER_STRATEGY");
+                //        //Note that if you're truly bent on doing this, then see FunctionValues.getRangeScorer
+                //    }
+
+                //    @Override
+                //        public Bits bits() throws IOException
+                //    {
+                //        //null Map context -- we simply don't have one. That's ok.
+                //        final FunctionValues predFuncValues = predicateValueSource.getValues(null, context);
+
+                //          return new Bits()
+                //    {
+
+                //        @Override
+                //            public boolean get(int index)
+                //    {
+                //        if (acceptDocs != null && !acceptDocs.get(index))
+                //            return false;
+                //        return predFuncValues.boolVal(index);
+                //    }
+
+                //    @Override
+                //            public int length()
+                //    {
+                //        return context.reader().maxDoc();
+                //    }
+                //};
+                //  }
+                //};
+            }
+
+            internal class DocIdSetAnonymousHelper : DocIdSet
+            {
+                private readonly PredicateValueSourceFilter outerInstance;
+                private readonly AtomicReaderContext context;
+                private readonly Bits acceptDocs;
+
+                public DocIdSetAnonymousHelper(PredicateValueSourceFilter outerInstance, AtomicReaderContext context, Bits acceptDocs)
+                {
+                    this.outerInstance = outerInstance;
+                    this.context = context;
+                    this.acceptDocs = acceptDocs;
+                }
+
+                public override DocIdSetIterator GetIterator()
+                {
+                    throw new NotSupportedException(
+                        "Iteration is too slow; instead try FilteredQuery.QUERY_FIRST_FILTER_STRATEGY");
+                        //Note that if you're truly bent on doing this, then see FunctionValues.getRangeScorer
+                }
+
+                public override Bits GetBits()
+                {
+                    //null Map context -- we simply don't have one. That's ok.
+                    FunctionValues predFuncValues = outerInstance.predicateValueSource.GetValues(null, context);
+
+                    return new BitsAnonymousHelper(this, predFuncValues, context, acceptDocs);
+                }
+
+                internal class BitsAnonymousHelper : Bits
+                {
+                    private readonly DocIdSetAnonymousHelper outerInstance;
+                    private readonly FunctionValues predFuncValues;
+                    private readonly AtomicReaderContext context;
+                    private readonly Bits acceptDocs;
+
+                    public BitsAnonymousHelper(DocIdSetAnonymousHelper outerInstance, FunctionValues predFuncValues, AtomicReaderContext context, Bits acceptDocs)
+                    {
+                        this.outerInstance = outerInstance;
+                        this.predFuncValues = predFuncValues;
+                        this.context = context;
+                        this.acceptDocs = acceptDocs;
+                    }
+
+                    public bool Get(int index)
+                    {
+                        if (acceptDocs != null && !acceptDocs.Get(index))
+                            return false;
+                        return predFuncValues.BoolVal(index);
+                    }
+
+                    public int Length()
+                    {
+                        return context.Reader.MaxDoc;
+                    }
+                }
+            }
+
+            public override bool Equals(object o)
+            {
+                if (this == o) return true;
+                if (o == null || GetType() != o.GetType()) return false;
+
+                PredicateValueSourceFilter that = (PredicateValueSourceFilter)o;
+
+                if (!predicateValueSource.Equals(that.predicateValueSource)) return false;
+
+                return true;
+            }
+
+
+            public override int GetHashCode()
+            {
+                return predicateValueSource.GetHashCode();
+            }
+        }//PredicateValueSourceFilter
+
+        /**
+         * Implements a ValueSource by deserializing a Shape in from BinaryDocValues using BinaryCodec.
+         * @see #makeShapeValueSource()
+         */
+        internal class ShapeDocValueSource : ValueSource
+        {
+            private readonly SerializedDVStrategy outerInstance;
+            private readonly string fieldName;
+            private readonly BinaryCodec binaryCodec;//spatial4n
+
+            internal ShapeDocValueSource(SerializedDVStrategy outerInstance, string fieldName, BinaryCodec binaryCodec)
+            {
+                this.outerInstance = outerInstance;
+                this.fieldName = fieldName;
+                this.binaryCodec = binaryCodec;
+            }
+
+            public override FunctionValues GetValues(IDictionary context, AtomicReaderContext readerContext)
+            {
+                BinaryDocValues docValues = readerContext.AtomicReader.GetBinaryDocValues(fieldName);
+
+                return new FuctionValuesAnonymousHelper(this, docValues);
+
+                //      return new FunctionValues()
+                //{
+                //    int bytesRefDoc = -1;
+                //    BytesRef bytesRef = new BytesRef();//scratch
+
+                //    bool fillBytes(int doc) {
+                //        if (bytesRefDoc != doc)
+                //        {
+                //            docValues.Get(doc, bytesRef);
+                //            bytesRefDoc = doc;
+                //        }
+                //        return bytesRef.length != 0;
+                //    }
+
+                //    @Override
+                //        public boolean exists(int doc)
+                //{
+                //    return fillBytes(doc);
+                //}
+
+                //@Override
+                //        public boolean bytesVal(int doc, BytesRef target)
+                //{
+                //    if (fillBytes(doc))
+                //    {
+                //        target.bytes = bytesRef.bytes;
+                //        target.offset = bytesRef.offset;
+                //        target.length = bytesRef.length;
+                //        return true;
+                //    }
+                //    else
+                //    {
+                //        target.length = 0;
+                //        return false;
+                //    }
+                //}
+
+                //@Override
+                //        public Object objectVal(int docId)
+                //{
+                //    if (!fillBytes(docId))
+                //        return null;
+                //    DataInputStream dataInput = new DataInputStream(
+                //        new ByteArrayInputStream(bytesRef.bytes, bytesRef.offset, bytesRef.length));
+                //    try
+                //    {
+                //        return binaryCodec.readShape(dataInput);
+                //    }
+                //    catch (IOException e)
+                //    {
+                //        throw new RuntimeException(e);
+                //    }
+                //}
+
+                //@Override
+                //        public Explanation explain(int doc)
+                //{
+                //    return new Explanation(Float.NaN, toString(doc));
+                //}
+
+                //@Override
+                //        public String toString(int doc)
+                //{
+                //    return description() + "=" + objectVal(doc);//TODO truncate?
+                //}
+
+                //      };
+            }
+
+            internal class FuctionValuesAnonymousHelper : FunctionValues
+            {
+                private readonly ShapeDocValueSource outerInstance;
+                private readonly BinaryDocValues docValues;
+
+                public FuctionValuesAnonymousHelper(ShapeDocValueSource outerInstance, BinaryDocValues docValues)
+                {
+                    this.outerInstance = outerInstance;
+                    this.docValues = docValues;
+                }
+
+                private int bytesRefDoc = -1;
+                private BytesRef bytesRef = new BytesRef();//scratch
+
+                internal bool FillBytes(int doc)
+                {
+                    if (bytesRefDoc != doc)
+                    {
+                        docValues.Get(doc, bytesRef);
+                        bytesRefDoc = doc;
+                    }
+                    return bytesRef.Length != 0;
+                }
+
+                public override bool Exists(int doc)
+                {
+                    return FillBytes(doc);
+                }
+
+                public override bool BytesVal(int doc, BytesRef target)
+                {
+                    if (FillBytes(doc))
+                    {
+                        target.Bytes = bytesRef.Bytes;
+                        target.Offset = bytesRef.Offset;
+                        target.Length = bytesRef.Length;
+                        return true;
+                    }
+                    else
+                    {
+                        target.Length = 0;
+                        return false;
+                    }
+                }
+
+                public override object ObjectVal(int docId)
+                {
+                    if (!FillBytes(docId))
+                        return null;
+                    BinaryReader dataInput = new BinaryReader(
+                        new MemoryStream(bytesRef.Bytes, bytesRef.Offset, bytesRef.Length));
+                    try
+                    {
+                        return outerInstance.binaryCodec.ReadShape(dataInput);
+                    }
+                    catch (IOException e)
+                    {
+                        throw new ApplicationException(e.Message, e);
+                    }
+                }
+
+                public override string ToString(int doc)
+                {
+                    return outerInstance.Description + "=" + ObjectVal(doc);//TODO truncate?
+                }
+            }
+
+            public override bool Equals(object o)
+            {
+                if (this == o) return true;
+                if (o == null || GetType() != o.GetType()) return false;
+
+                ShapeDocValueSource that = (ShapeDocValueSource)o;
+
+                if (!fieldName.Equals(that.fieldName)) return false;
+
+                return true;
+            }
+
+            public override int GetHashCode()
+            {
+                int result = fieldName.GetHashCode();
+                return result;
+            }
+
+            public override string Description
+            {
+                get
+                {
+                    return "shapeDocVal(" + fieldName + ")";
+                }
+            }
+
+        }//ShapeDocValueSource
+    }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Util/DistanceToShapeValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Util/DistanceToShapeValueSource.cs b/src/Lucene.Net.Spatial/Util/DistanceToShapeValueSource.cs
new file mode 100644
index 0000000..721677c
--- /dev/null
+++ b/src/Lucene.Net.Spatial/Util/DistanceToShapeValueSource.cs
@@ -0,0 +1,151 @@
+using Lucene.Net.Index;
+using Lucene.Net.Queries.Function;
+using Lucene.Net.Queries.Function.DocValues;
+using Lucene.Net.Search;
+using Lucene.Net.Support;
+using Spatial4n.Core.Context;
+using Spatial4n.Core.Distance;
+using Spatial4n.Core.Shapes;
+using System.Collections;
+
+namespace Lucene.Net.Spatial.Util
+{
+    /*
+     * 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>
+    /// The distance from a provided Point to a Point retrieved from a ValueSource via
+    /// <see cref="FunctionValues.ObjectVal(int)"/>. The distance
+    /// is calculated via a <see cref="IDistanceCalculator"/>.
+    /// 
+    /// @lucene.experimental
+    /// </summary>
+    public class DistanceToShapeValueSource : ValueSource
+    {
+        private readonly ValueSource shapeValueSource;
+        private readonly IPoint queryPoint;
+        private readonly double multiplier;
+        private readonly IDistanceCalculator distCalc;
+
+        //TODO if FunctionValues returns NaN; will things be ok?
+        private readonly double nullValue;//computed
+
+        public DistanceToShapeValueSource(ValueSource shapeValueSource, IPoint queryPoint,
+                                          double multiplier, SpatialContext ctx)
+        {
+            this.shapeValueSource = shapeValueSource;
+            this.queryPoint = queryPoint;
+            this.multiplier = multiplier;
+            this.distCalc = ctx.DistCalc;
+            this.nullValue =
+                (ctx.IsGeo ? 180 * multiplier : double.MaxValue);
+        }
+
+        public override string Description
+        {
+            get { return "distance(" + queryPoint + " to " + shapeValueSource.Description + ")*" + multiplier + ")"; }
+        }
+
+        public override void CreateWeight(IDictionary context, IndexSearcher searcher)
+        {
+            shapeValueSource.CreateWeight(context, searcher);
+        }
+
+        internal class DoubleDocValuesAnonymousHelper : DoubleDocValues
+        {
+            private readonly DistanceToShapeValueSource outerInstance;
+            private readonly FunctionValues shapeValues;
+
+            public DoubleDocValuesAnonymousHelper(DistanceToShapeValueSource outerInstance, FunctionValues shapeValues)
+                : base(outerInstance)
+            {
+                this.outerInstance = outerInstance;
+                this.shapeValues = shapeValues;
+            }
+
+            public override double DoubleVal(int doc)
+            {
+                IShape shape = (IShape)shapeValues.ObjectVal(doc);
+                if (shape == null || shape.IsEmpty)
+                    return outerInstance.nullValue;
+                IPoint pt = shape.Center;
+                return outerInstance.distCalc.Distance(outerInstance.queryPoint, pt) * outerInstance.multiplier;
+            }
+
+            public override Explanation Explain(int doc)
+            {
+                Explanation exp = base.Explain(doc);
+                exp.AddDetail(shapeValues.Explain(doc));
+                return exp;
+            }
+        }
+
+        public override FunctionValues GetValues(IDictionary context, AtomicReaderContext readerContext)
+        {
+            FunctionValues shapeValues = shapeValueSource.GetValues(context, readerContext);
+
+            return new DoubleDocValuesAnonymousHelper(this, shapeValues);
+
+            //return new DoubleDocValues(this)
+            //    {
+            //        @Override
+            //  public double doubleVal(int doc)
+            //    {
+            //        Shape shape = (Shape)shapeValues.objectVal(doc);
+            //        if (shape == null || shape.isEmpty())
+            //            return nullValue;
+            //        Point pt = shape.getCenter();
+            //        return distCalc.distance(queryPoint, pt) * multiplier;
+            //    }
+
+            //    @Override
+            //  public Explanation explain(int doc)
+            //    {
+            //        Explanation exp = super.explain(doc);
+            //        exp.addDetail(shapeValues.explain(doc));
+            //        return exp;
+            //    }
+            //};
+        }
+
+        public override bool Equals(object o)
+        {
+            if (this == o) return true;
+            if (o == null || GetType() != o.GetType()) return false;
+
+            DistanceToShapeValueSource that = (DistanceToShapeValueSource)o;
+
+            if (!queryPoint.Equals(that.queryPoint)) return false;
+            if (that.multiplier.CompareTo(multiplier) != 0) return false;
+            if (!shapeValueSource.Equals(that.shapeValueSource)) return false;
+            if (!distCalc.Equals(that.distCalc)) return false;
+
+            return true;
+        }
+
+        public override int GetHashCode()
+        {
+            int result;
+            long temp;
+            result = shapeValueSource.GetHashCode();
+            result = 31 * result + queryPoint.GetHashCode();
+            temp = Number.DoubleToLongBits(multiplier);
+            result = 31 * result + (int)(temp ^ ((long)((ulong)temp) >> 32));
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Util/ShapePredicateValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Util/ShapePredicateValueSource.cs b/src/Lucene.Net.Spatial/Util/ShapePredicateValueSource.cs
new file mode 100644
index 0000000..fd88f40
--- /dev/null
+++ b/src/Lucene.Net.Spatial/Util/ShapePredicateValueSource.cs
@@ -0,0 +1,146 @@
+using Lucene.Net.Index;
+using Lucene.Net.Queries.Function;
+using Lucene.Net.Queries.Function.DocValues;
+using Lucene.Net.Search;
+using Lucene.Net.Spatial.Queries;
+using Spatial4n.Core.Shapes;
+using System.Collections;
+
+namespace Lucene.Net.Spatial.Util
+{
+    /*
+     * 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 boolean ValueSource that compares a shape from a provided ValueSource with a given Shape and sees
+    /// if it matches a given <see cref="SpatialOperation"/> (the predicate).
+    /// 
+    /// @lucene.experimental
+    /// </summary>
+    public class ShapePredicateValueSource : ValueSource
+    {
+        private readonly ValueSource shapeValuesource;//the left hand side
+        private readonly SpatialOperation op;
+        private readonly IShape queryShape;//the right hand side (constant)
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="shapeValuesource">
+        /// Must yield <see cref="IShape"/> instances from it's objectVal(doc). If null
+        /// then the result is false. This is the left-hand (indexed) side.
+        /// </param>
+        /// <param name="op">the predicate</param>
+        /// <param name="queryShape">The shape on the right-hand (query) side.</param>
+        public ShapePredicateValueSource(ValueSource shapeValuesource, SpatialOperation op, IShape queryShape)
+        {
+            this.shapeValuesource = shapeValuesource;
+            this.op = op;
+            this.queryShape = queryShape;
+        }
+
+
+        public override string Description
+        {
+            get { return shapeValuesource + " " + op + " " + queryShape; }
+        }
+
+
+        public override void CreateWeight(IDictionary context, IndexSearcher searcher)
+        {
+            shapeValuesource.CreateWeight(context, searcher);
+        }
+
+        internal class BoolDocValuesAnonymousHelper : BoolDocValues
+        {
+            private readonly ShapePredicateValueSource outerInstance;
+            private readonly FunctionValues shapeValues;
+
+            public BoolDocValuesAnonymousHelper(ShapePredicateValueSource outerInstance, FunctionValues shapeValues)
+                : base(outerInstance)
+            {
+                this.outerInstance = outerInstance;
+                this.shapeValues = shapeValues;
+            }
+
+            public override bool BoolVal(int doc)
+            {
+                IShape indexedShape = (IShape)shapeValues.ObjectVal(doc);
+                if (indexedShape == null)
+                    return false;
+                return outerInstance.op.Evaluate(indexedShape, outerInstance.queryShape);
+            }
+
+            public override Explanation Explain(int doc)
+            {
+                Explanation exp = base.Explain(doc);
+                exp.AddDetail(shapeValues.Explain(doc));
+                return exp;
+            }
+        }
+
+        public override FunctionValues GetValues(IDictionary context, AtomicReaderContext readerContext)
+        {
+            FunctionValues shapeValues = shapeValuesource.GetValues(context, readerContext);
+
+            return new BoolDocValuesAnonymousHelper(this, shapeValues);
+
+            //return new BoolDocValues(this)
+            //    {
+            //        @Override
+            //  public boolean boolVal(int doc)
+            //    {
+            //        Shape indexedShape = (Shape)shapeValues.objectVal(doc);
+            //        if (indexedShape == null)
+            //            return false;
+            //        return op.evaluate(indexedShape, queryShape);
+            //    }
+
+            //    @Override
+            //  public Explanation explain(int doc)
+            //    {
+            //        Explanation exp = super.explain(doc);
+            //        exp.addDetail(shapeValues.explain(doc));
+            //        return exp;
+            //    }
+            //};
+        }
+
+
+        public override bool Equals(object o)
+        {
+            if (this == o) return true;
+            if (o == null || GetType() != o.GetType()) return false;
+
+            ShapePredicateValueSource that = (ShapePredicateValueSource)o;
+
+            if (!shapeValuesource.Equals(that.shapeValuesource)) return false;
+            if (!op.Equals(that.op)) return false;
+            if (!queryShape.Equals(that.queryShape)) return false;
+
+            return true;
+        }
+
+        public override int GetHashCode()
+        {
+            int result = shapeValuesource.GetHashCode();
+            result = 31 * result + op.GetHashCode();
+            result = 31 * result + queryShape.GetHashCode();
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Spatial/Vector/PointVectorStrategy.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Spatial/Vector/PointVectorStrategy.cs b/src/Lucene.Net.Spatial/Vector/PointVectorStrategy.cs
index 5c0d264..dcbe259 100644
--- a/src/Lucene.Net.Spatial/Vector/PointVectorStrategy.cs
+++ b/src/Lucene.Net.Spatial/Vector/PointVectorStrategy.cs
@@ -125,7 +125,7 @@ namespace Lucene.Net.Spatial.Vector
                 return new ConstantScoreQuery(vsf);
             }
 
-            throw new InvalidOperationException("Only Rectangles and Circles are currently supported, " +
+            throw new NotSupportedException("Only Rectangles and Circles are currently supported, " +
                                             "found [" + shape.GetType().Name + "]"); //TODO
         }
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.TestFramework/JavaCompatibility/LuceneTestCase.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.TestFramework/JavaCompatibility/LuceneTestCase.cs b/src/Lucene.Net.TestFramework/JavaCompatibility/LuceneTestCase.cs
index 841feaf..f0dc587 100644
--- a/src/Lucene.Net.TestFramework/JavaCompatibility/LuceneTestCase.cs
+++ b/src/Lucene.Net.TestFramework/JavaCompatibility/LuceneTestCase.cs
@@ -3,6 +3,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using NUnit.Framework;
+using System.Diagnostics;
 
 namespace Lucene.Net.Util
 {
@@ -137,5 +138,108 @@ namespace Lucene.Net.Util
         {
             return new HashSet<T>(args);
         }
+
+        protected int randomInt(int max)
+        {
+            return randomIntBetween(0, max);
+        }
+
+        protected int randomIntBetween(int min, int max)
+        {
+            Debug.Assert(max >= min, "max must be >= min: " + min + ", " + max);
+            long range = (long)max - (long)min;
+            if (range < int.MaxValue)
+            {
+                return min + Random().nextInt(1 + (int)range);
+            }
+            else
+            {
+                return toIntExact(min + Random().Next(1 + (int)range));
+            }
+        }
+
+        private static int toIntExact(long value)
+        {
+            if (value > int.MaxValue)
+            {
+                throw new ArithmeticException("Overflow: " + value);
+            }
+            else
+            {
+                return (int)value;
+            }
+        }
+
+        private double nextNextGaussian;
+        private bool haveNextNextGaussian = false;
+
+        /**
+         * Returns the next pseudorandom, Gaussian ("normally") distributed
+         * {@code double} value with mean {@code 0.0} and standard
+         * deviation {@code 1.0} from this random number generator's sequence.
+         * <p>
+         * The general contract of {@code nextGaussian} is that one
+         * {@code double} value, chosen from (approximately) the usual
+         * normal distribution with mean {@code 0.0} and standard deviation
+         * {@code 1.0}, is pseudorandomly generated and returned.
+         *
+         * <p>The method {@code nextGaussian} is implemented by class
+         * {@code Random} as if by a threadsafe version of the following:
+         *  <pre> {@code
+         * private double nextNextGaussian;
+         * private boolean haveNextNextGaussian = false;
+         *
+         * public double nextGaussian() {
+         *   if (haveNextNextGaussian) {
+         *     haveNextNextGaussian = false;
+         *     return nextNextGaussian;
+         *   } else {
+         *     double v1, v2, s;
+         *     do {
+         *       v1 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
+         *       v2 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
+         *       s = v1 * v1 + v2 * v2;
+         *     } while (s >= 1 || s == 0);
+         *     double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+         *     nextNextGaussian = v2 * multiplier;
+         *     haveNextNextGaussian = true;
+         *     return v1 * multiplier;
+         *   }
+         * }}</pre>
+         * This uses the <i>polar method</i> of G. E. P. Box, M. E. Muller, and
+         * G. Marsaglia, as described by Donald E. Knuth in <i>The Art of
+         * Computer Programming</i>, Volume 3: <i>Seminumerical Algorithms</i>,
+         * section 3.4.1, subsection C, algorithm P. Note that it generates two
+         * independent values at the cost of only one call to {@code StrictMath.log}
+         * and one call to {@code StrictMath.sqrt}.
+         *
+         * @return the next pseudorandom, Gaussian ("normally") distributed
+         *         {@code double} value with mean {@code 0.0} and
+         *         standard deviation {@code 1.0} from this random number
+         *         generator's sequence
+         */
+        public double randomGaussian()
+        {
+            // See Knuth, ACP, Section 3.4.1 Algorithm C.
+            if (haveNextNextGaussian)
+            {
+                haveNextNextGaussian = false;
+                return nextNextGaussian;
+            }
+            else
+            {
+                double v1, v2, s;
+                do
+                {
+                    v1 = 2 * Random().NextDouble() - 1; // between -1 and 1
+                    v2 = 2 * Random().NextDouble() - 1; // between -1 and 1
+                    s = v1 * v1 + v2 * v2;
+                } while (s >= 1 || s == 0);
+                double multiplier = Math.Sqrt(-2 * Math.Log(s) / s);
+                nextNextGaussian = v2 * multiplier;
+                haveNextNextGaussian = true;
+                return v1 * multiplier;
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs b/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs
index 04abb39..4685998 100644
--- a/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs
+++ b/src/Lucene.Net.TestFramework/JavaCompatibility/SystemTypesHelpers.cs
@@ -203,7 +203,32 @@ namespace Lucene.Net
 
         public static bool removeAll<T>(this ISet<T> s, IEnumerable<T> list)
         {
-            return s.removeAll(list);
+            bool modified = false;
+
+            if (s.Count > list.Count())
+            {
+                for (var i = list.GetEnumerator(); i.MoveNext();)
+                    modified |= s.Remove(i.Current);
+            }
+            else
+            {
+                List<T> toRemove = new List<T>();
+
+                for (var i = s.GetEnumerator(); i.MoveNext();)
+                {
+                    if (list.Contains(i.Current))
+                    {
+                        toRemove.Add(i.Current);
+                    }
+                }
+
+                foreach (var i in toRemove)
+                {
+                    s.Remove(i);
+                    modified = true;
+                }
+            }
+            return modified;
         }
 
         public static void clear<T>(this ISet<T> s)

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/d8c73530/src/Lucene.Net.Tests.Spatial/DistanceStrategyTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Spatial/DistanceStrategyTest.cs b/src/Lucene.Net.Tests.Spatial/DistanceStrategyTest.cs
new file mode 100644
index 0000000..5f0aa7b
--- /dev/null
+++ b/src/Lucene.Net.Tests.Spatial/DistanceStrategyTest.cs
@@ -0,0 +1,155 @@
+using Lucene.Net.Randomized.Generators;
+using Lucene.Net.Spatial.Prefix;
+using Lucene.Net.Spatial.Prefix.Tree;
+using Lucene.Net.Spatial.Serialized;
+using Lucene.Net.Spatial.Vector;
+using Lucene.Net.Support;
+using NUnit.Framework;
+using Spatial4n.Core.Context;
+using Spatial4n.Core.Shapes;
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Spatial
+{
+    /*
+     * 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.
+     */
+
+    public class DistanceStrategyTest : StrategyTestCase
+    {
+        //@ParametersFactory
+        public static IList<Object[]> Parameters()
+        {
+            List<Object[]> ctorArgs = new List<object[]>();
+
+            SpatialContext ctx = SpatialContext.GEO;
+            SpatialPrefixTree grid;
+            SpatialStrategy strategy;
+
+            grid = new QuadPrefixTree(ctx, 25);
+            strategy = new RecursivePrefixTreeStrategy(grid, "recursive_quad");
+            ctorArgs.Add(new Object[] { new Param(strategy) });
+
+            grid = new GeohashPrefixTree(ctx, 12);
+            strategy = new TermQueryPrefixTreeStrategy(grid, "termquery_geohash");
+            ctorArgs.Add(new Object[] { new Param(strategy) });
+
+            strategy = new PointVectorStrategy(ctx, "pointvector");
+            ctorArgs.Add(new Object[] { new Param(strategy) });
+
+            strategy = new SerializedDVStrategy(ctx, "serialized");
+            ctorArgs.Add(new Object[] { new Param(strategy) });
+
+            return ctorArgs;
+        }
+
+        // this is a hack for clover!
+        public class Param
+        {
+            internal SpatialStrategy strategy;
+
+            internal Param(SpatialStrategy strategy)
+            {
+                this.strategy = strategy;
+            }
+
+
+            public override String ToString()
+            {
+                return strategy.FieldName;
+            }
+        }
+
+        //  private String fieldName;
+
+        //public DistanceStrategyTest(Param param)
+        //{
+        //    SpatialStrategy strategy = param.strategy;
+        //    this.ctx = strategy.SpatialContext;
+        //    this.strategy = strategy;
+        //}
+
+        public override void SetUp()
+        {
+            base.SetUp();
+            SpatialStrategy strategy = ((Param)(RandomInts.RandomFrom(Random(), Parameters()))[0]).strategy;
+            this.ctx = strategy.SpatialContext;
+            this.strategy = strategy;
+        }
+
+
+        protected override bool NeedsDocValues()
+        {
+            return (strategy is SerializedDVStrategy);
+        }
+
+        [Test]
+        public virtual void TestDistanceOrder()
+        {
+            adoc("100", ctx.MakePoint(2, 1));
+            adoc("101", ctx.MakePoint(-1, 4));
+            adoc("103", (IShape)null);//test score for nothing
+            adoc("999", ctx.MakePoint(2, 1));//test deleted
+            Commit();
+            DeleteDoc("999");
+            Commit();
+            //FYI distances are in docid order
+            checkDistValueSource(ctx.MakePoint(4, 3), 2.8274937f, 5.0898066f, 180f);
+            checkDistValueSource(ctx.MakePoint(0, 4), 3.6043684f, 0.9975641f, 180f);
+        }
+
+        [Test]
+        public virtual void TestRecipScore()
+        {
+            IPoint p100 = ctx.MakePoint(2, 1);
+            adoc("100", p100);
+            IPoint p101 = ctx.MakePoint(-1, 4);
+            adoc("101", p101);
+            adoc("103", (IShape)null);//test score for nothing
+            adoc("999", ctx.MakePoint(2, 1));//test deleted
+            Commit();
+            DeleteDoc("999");
+            Commit();
+
+            double dist = ctx.DistCalc.Distance(p100, p101);
+            IShape queryShape = ctx.MakeCircle(2.01, 0.99, dist);
+            CheckValueSource(strategy.MakeRecipDistanceValueSource(queryShape),
+            new float[] { 1.00f, 0.10f, 0f }, 0.09f);
+        }
+
+        // @Override
+        // protected Document newDoc(String id, Shape shape) {
+        //   //called by adoc().  Make compatible with BBoxStrategy.
+        //   if (shape != null && strategy instanceof BBoxStrategy)
+        //     shape = ctx.makeRectangle(shape.getCenter(), shape.getCenter());
+        //   return super.newDoc(id, shape);
+        // }
+
+        internal void checkDistValueSource(IPoint pt, params float[] distances)
+        {
+            float multiplier = (float)Random().NextDouble() * 100f;
+            float[]
+            dists2 = Arrays.CopyOf(distances, distances.Length);
+            for (int i = 0; i < dists2.Length; i++)
+            {
+                dists2[i] *= multiplier;
+            }
+            CheckValueSource(strategy.MakeDistanceValueSource(pt, multiplier), dists2, 1.0e-3f);
+        }
+
+    }
+}


Mime
View raw message