You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by cc...@apache.org on 2013/04/03 19:40:16 UTC

[33/51] [partial] Mass convert mixed tabs to spaces

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/62f018ab/src/contrib/Spatial/BBox/BBoxStrategy.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/BBox/BBoxStrategy.cs b/src/contrib/Spatial/BBox/BBoxStrategy.cs
index b97bb17..f14af08 100644
--- a/src/contrib/Spatial/BBox/BBoxStrategy.cs
+++ b/src/contrib/Spatial/BBox/BBoxStrategy.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.
@@ -36,9 +36,9 @@ namespace Lucene.Net.Spatial.BBox
         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).
-		 */
+         * 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;
@@ -130,356 +130,356 @@ namespace Lucene.Net.Spatial.BBox
         }
 
         public override Filter MakeFilter(SpatialArgs args)
-		{
+        {
             return new QueryWrapperFilter(MakeSpatialQuery(args));
-		}
+        }
 
-		private Query MakeSpatialQuery(SpatialArgs 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;
-		}
-	}
+            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/62f018ab/src/contrib/Spatial/BBox/DistanceSimilarity.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/BBox/DistanceSimilarity.cs b/src/contrib/Spatial/BBox/DistanceSimilarity.cs
index 98273f4..9b7c88b 100644
--- a/src/contrib/Spatial/BBox/DistanceSimilarity.cs
+++ b/src/contrib/Spatial/BBox/DistanceSimilarity.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/62f018ab/src/contrib/Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs b/src/contrib/Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs
index 614226c..5a7c554 100644
--- a/src/contrib/Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs
+++ b/src/contrib/Spatial/Prefix/PointPrefixTreeFieldCacheProvider.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.
@@ -29,23 +29,23 @@ namespace Lucene.Net.Spatial.Prefix
     /// 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 class PointPrefixTreeFieldCacheProvider : ShapeFieldCacheProvider<Point>
+    {
+        readonly SpatialPrefixTree grid; //
 
-		public PointPrefixTreeFieldCacheProvider(SpatialPrefixTree grid, String shapeField, int defaultSize)
-			: base(shapeField, defaultSize)
-		{
-			this.grid = 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;
+        //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;
-		}
-	}
+        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/62f018ab/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs b/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs
index e300b4d..e15f6cd 100644
--- a/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs
+++ b/src/contrib/Spatial/Prefix/PrefixTreeStrategy.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.
@@ -67,110 +67,110 @@ namespace Lucene.Net.Spatial.Prefix
         /// </summary>
         public double DistErrPct { get; set; }
 
-		public override AbstractField[] CreateIndexableFields(Shape shape)
-		{
-		    double distErr = SpatialArgs.CalcDistanceFromErrPct(shape, distErrPct, ctx);
-		    return CreateIndexableFields(shape, distErr);
-		}
+        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
+            //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 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;
-		}
+                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();
+        {
+            var p = (PointPrefixTreeFieldCacheProvider)GetCacheProvider();
             return new ShapeFieldCacheDistanceValueSource(ctx, p, queryPoint);
-		}
+        }
 
-		public SpatialPrefixTree GetGrid()
-		{
-			return grid;
-		}
-	}
+        public SpatialPrefixTree GetGrid()
+        {
+            return grid;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/62f018ab/src/contrib/Spatial/Prefix/RecursivePrefixTreeFilter.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/Prefix/RecursivePrefixTreeFilter.cs b/src/contrib/Spatial/Prefix/RecursivePrefixTreeFilter.cs
index bb12704..ce0d0d9 100644
--- a/src/contrib/Spatial/Prefix/RecursivePrefixTreeFilter.cs
+++ b/src/contrib/Spatial/Prefix/RecursivePrefixTreeFilter.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.
@@ -26,16 +26,16 @@ using Spatial4n.Core.Shapes;
 
 namespace Lucene.Net.Spatial.Prefix
 {
-	/// <summary>
-	/// Performs a spatial intersection filter against a field indexed with {@link SpatialPrefixTree}, a Trie.
-	/// SPT yields terms (grids) at length 1 and at greater lengths corresponding to greater precisions.
-	/// This filter recursively traverses each grid length and uses methods on {@link Shape} to efficiently know
-	/// that all points at a prefix fit in the shape or not to either short-circuit unnecessary traversals or to efficiently
-	/// load all enclosed points.
-	/// </summary>
-	public class RecursivePrefixTreeFilter : Filter
-	{
-		/* TODOs for future:
+    /// <summary>
+    /// Performs a spatial intersection filter against a field indexed with {@link SpatialPrefixTree}, a Trie.
+    /// SPT yields terms (grids) at length 1 and at greater lengths corresponding to greater precisions.
+    /// This filter recursively traverses each grid length and uses methods on {@link Shape} to efficiently know
+    /// that all points at a prefix fit in the shape or not to either short-circuit unnecessary traversals or to efficiently
+    /// load all enclosed points.
+    /// </summary>
+    public class RecursivePrefixTreeFilter : Filter
+    {
+        /* TODOs for future:
 
 Can a polygon query shape be optimized / made-simpler at recursive depths (e.g. intersection of shape + cell box)
 
@@ -48,142 +48,142 @@ if (!scan) {
   long termsThreshold = (long) estimateNumberIndexedTerms(cell.length(),queryShape.getDocFreqExpenseThreshold(cell));
   long thisOrd = termsEnum.ord();
   scan = (termsEnum.seek(thisOrd+termsThreshold+1) == TermsEnum.SeekStatus.END
-		  || !cell.contains(termsEnum.term()));
+          || !cell.contains(termsEnum.term()));
   termsEnum.seek(thisOrd);//return to last position
 }
 
 */
 
-		private readonly String fieldName;
-		private readonly SpatialPrefixTree grid;
-		private readonly Shape queryShape;
-		private readonly int prefixGridScanLevel;//at least one less than grid.getMaxLevels()
-		private readonly int detailLevel;
-
-		public RecursivePrefixTreeFilter(String fieldName, SpatialPrefixTree grid, Shape queryShape, int prefixGridScanLevel,
-							 int detailLevel)
-		{
-			this.fieldName = fieldName;
-			this.grid = grid;
-			this.queryShape = queryShape;
-			this.prefixGridScanLevel = Math.Max(1, Math.Min(prefixGridScanLevel, grid.GetMaxLevels() - 1));
-			this.detailLevel = detailLevel;
-			Debug.Assert(detailLevel <= grid.GetMaxLevels());
-		}
-
-		public override DocIdSet GetDocIdSet(Index.IndexReader reader /*, Bits acceptDocs*/)
-		{
-			var bits = new OpenBitSet(reader.MaxDoc);
-			var terms = new TermsEnumCompatibility(reader, fieldName);
-			var term = terms.Next();
-			if (term == null)
-				return null;
-			Node scanCell = null;
-
-			//cells is treated like a stack. LinkedList conveniently has bulk add to beginning. It's in sorted order so that we
-			//  always advance forward through the termsEnum index.
-			var cells = new LinkedList<Node>(
-				grid.GetWorldNode().GetSubCells(queryShape));
-
-			//This is a recursive algorithm that starts with one or more "big" cells, and then recursively dives down into the
-			// first such cell that intersects with the query shape.  It's a depth first traversal because we don't move onto
-			// the next big cell (breadth) until we're completely done considering all smaller cells beneath it. For a given
-			// cell, if it's *within* the query shape then we can conveniently short-circuit the depth traversal and
-			// grab all documents assigned to this cell/term.  For an intersection of the cell and query shape, we either
-			// recursively step down another grid level or we decide heuristically (via prefixGridScanLevel) that there aren't
-			// that many points, and so we scan through all terms within this cell (i.e. the term starts with the cell's term),
-			// seeing which ones are within the query shape.
-			while (cells.Count > 0)
-			{
-				Node cell = cells.First.Value; cells.RemoveFirst();
-				var cellTerm = cell.GetTokenString();
-				var seekStat = terms.Seek(cellTerm);
-				if (seekStat == TermsEnumCompatibility.SeekStatus.END)
-					break;
-				if (seekStat == TermsEnumCompatibility.SeekStatus.NOT_FOUND)
-					continue;
-				if (cell.GetLevel() == detailLevel || cell.IsLeaf())
-				{
-					terms.Docs(bits);
-				}
-				else
-				{//any other intersection
-					//If the next indexed term is the leaf marker, then add all of them
-					var nextCellTerm = terms.Next();
-					Debug.Assert(nextCellTerm.Text.StartsWith(cellTerm));
-					scanCell = grid.GetNode(nextCellTerm.Text, scanCell);
-					if (scanCell.IsLeaf())
-					{
-						terms.Docs(bits);
-						term = terms.Next();//move pointer to avoid potential redundant addDocs() below
-					}
-
-					//Decide whether to continue to divide & conquer, or whether it's time to scan through terms beneath this cell.
-					// Scanning is a performance optimization trade-off.
-					bool scan = cell.GetLevel() >= prefixGridScanLevel;//simple heuristic
-
-					if (!scan)
-					{
-						//Divide & conquer
-						var lst = cell.GetSubCells(queryShape);
-						for (var i = lst.Count - 1; i >= 0; i--) //add to beginning
-						{
-							cells.AddFirst(lst[i]);
-						}
-					}
-					else
-					{
-						//Scan through all terms within this cell to see if they are within the queryShape. No seek()s.
-						for (var t = terms.Term(); t != null && t.Text.StartsWith(cellTerm); t = terms.Next())
-						{
-							scanCell = grid.GetNode(t.Text, scanCell);
-							int termLevel = scanCell.GetLevel();
-							if (termLevel > detailLevel)
-								continue;
-							if (termLevel == detailLevel || scanCell.IsLeaf())
-							{
-								//TODO should put more thought into implications of box vs point
-								Shape cShape = termLevel == grid.GetMaxLevels() ? scanCell.GetCenter() : scanCell.GetShape();
+        private readonly String fieldName;
+        private readonly SpatialPrefixTree grid;
+        private readonly Shape queryShape;
+        private readonly int prefixGridScanLevel;//at least one less than grid.getMaxLevels()
+        private readonly int detailLevel;
+
+        public RecursivePrefixTreeFilter(String fieldName, SpatialPrefixTree grid, Shape queryShape, int prefixGridScanLevel,
+                             int detailLevel)
+        {
+            this.fieldName = fieldName;
+            this.grid = grid;
+            this.queryShape = queryShape;
+            this.prefixGridScanLevel = Math.Max(1, Math.Min(prefixGridScanLevel, grid.GetMaxLevels() - 1));
+            this.detailLevel = detailLevel;
+            Debug.Assert(detailLevel <= grid.GetMaxLevels());
+        }
+
+        public override DocIdSet GetDocIdSet(Index.IndexReader reader /*, Bits acceptDocs*/)
+        {
+            var bits = new OpenBitSet(reader.MaxDoc);
+            var terms = new TermsEnumCompatibility(reader, fieldName);
+            var term = terms.Next();
+            if (term == null)
+                return null;
+            Node scanCell = null;
+
+            //cells is treated like a stack. LinkedList conveniently has bulk add to beginning. It's in sorted order so that we
+            //  always advance forward through the termsEnum index.
+            var cells = new LinkedList<Node>(
+                grid.GetWorldNode().GetSubCells(queryShape));
+
+            //This is a recursive algorithm that starts with one or more "big" cells, and then recursively dives down into the
+            // first such cell that intersects with the query shape.  It's a depth first traversal because we don't move onto
+            // the next big cell (breadth) until we're completely done considering all smaller cells beneath it. For a given
+            // cell, if it's *within* the query shape then we can conveniently short-circuit the depth traversal and
+            // grab all documents assigned to this cell/term.  For an intersection of the cell and query shape, we either
+            // recursively step down another grid level or we decide heuristically (via prefixGridScanLevel) that there aren't
+            // that many points, and so we scan through all terms within this cell (i.e. the term starts with the cell's term),
+            // seeing which ones are within the query shape.
+            while (cells.Count > 0)
+            {
+                Node cell = cells.First.Value; cells.RemoveFirst();
+                var cellTerm = cell.GetTokenString();
+                var seekStat = terms.Seek(cellTerm);
+                if (seekStat == TermsEnumCompatibility.SeekStatus.END)
+                    break;
+                if (seekStat == TermsEnumCompatibility.SeekStatus.NOT_FOUND)
+                    continue;
+                if (cell.GetLevel() == detailLevel || cell.IsLeaf())
+                {
+                    terms.Docs(bits);
+                }
+                else
+                {//any other intersection
+                    //If the next indexed term is the leaf marker, then add all of them
+                    var nextCellTerm = terms.Next();
+                    Debug.Assert(nextCellTerm.Text.StartsWith(cellTerm));
+                    scanCell = grid.GetNode(nextCellTerm.Text, scanCell);
+                    if (scanCell.IsLeaf())
+                    {
+                        terms.Docs(bits);
+                        term = terms.Next();//move pointer to avoid potential redundant addDocs() below
+                    }
+
+                    //Decide whether to continue to divide & conquer, or whether it's time to scan through terms beneath this cell.
+                    // Scanning is a performance optimization trade-off.
+                    bool scan = cell.GetLevel() >= prefixGridScanLevel;//simple heuristic
+
+                    if (!scan)
+                    {
+                        //Divide & conquer
+                        var lst = cell.GetSubCells(queryShape);
+                        for (var i = lst.Count - 1; i >= 0; i--) //add to beginning
+                        {
+                            cells.AddFirst(lst[i]);
+                        }
+                    }
+                    else
+                    {
+                        //Scan through all terms within this cell to see if they are within the queryShape. No seek()s.
+                        for (var t = terms.Term(); t != null && t.Text.StartsWith(cellTerm); t = terms.Next())
+                        {
+                            scanCell = grid.GetNode(t.Text, scanCell);
+                            int termLevel = scanCell.GetLevel();
+                            if (termLevel > detailLevel)
+                                continue;
+                            if (termLevel == detailLevel || scanCell.IsLeaf())
+                            {
+                                //TODO should put more thought into implications of box vs point
+                                Shape cShape = termLevel == grid.GetMaxLevels() ? scanCell.GetCenter() : scanCell.GetShape();
                                 if (queryShape.Relate(cShape) == SpatialRelation.DISJOINT)
-									continue;
-
-								terms.Docs(bits);
-							}
-						}//term loop
-					}
-				}
-			}//cell loop
-
-			return bits;
-		}
-
-		public override string ToString()
-		{
-			return "GeoFilter{fieldName='" + fieldName + '\'' + ", shape=" + queryShape + '}';
-		}
-
-		public override bool Equals(object o)
-		{
-			if (this == o) return true;
-			var that = o as RecursivePrefixTreeFilter;
-
-			if (that == null) return false;
-
-			if (!fieldName.Equals(that.fieldName)) return false;
-			//note that we don't need to look at grid since for the same field it should be the same
-			if (prefixGridScanLevel != that.prefixGridScanLevel) return false;
-			if (detailLevel != that.detailLevel) return false;
-			if (!queryShape.Equals(that.queryShape)) return false;
-
-			return true;
-		}
-
-		public override int GetHashCode()
-		{
-			int result = fieldName.GetHashCode();
-			result = 31 * result + queryShape.GetHashCode();
-			result = 31 * result + detailLevel;
-			return result;
-		}
-	}
+                                    continue;
+
+                                terms.Docs(bits);
+                            }
+                        }//term loop
+                    }
+                }
+            }//cell loop
+
+            return bits;
+        }
+
+        public override string ToString()
+        {
+            return "GeoFilter{fieldName='" + fieldName + '\'' + ", shape=" + queryShape + '}';
+        }
+
+        public override bool Equals(object o)
+        {
+            if (this == o) return true;
+            var that = o as RecursivePrefixTreeFilter;
+
+            if (that == null) return false;
+
+            if (!fieldName.Equals(that.fieldName)) return false;
+            //note that we don't need to look at grid since for the same field it should be the same
+            if (prefixGridScanLevel != that.prefixGridScanLevel) return false;
+            if (detailLevel != that.detailLevel) return false;
+            if (!queryShape.Equals(that.queryShape)) return false;
+
+            return true;
+        }
+
+        public override int GetHashCode()
+        {
+            int result = fieldName.GetHashCode();
+            result = 31 * result + queryShape.GetHashCode();
+            result = 31 * result + detailLevel;
+            return result;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/62f018ab/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs b/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs
index e1f5718..d6fa681 100644
--- a/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs
+++ b/src/contrib/Spatial/Prefix/RecursivePrefixTreeStrategy.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.
@@ -22,41 +22,41 @@ using Spatial4n.Core.Shapes;
 
 namespace Lucene.Net.Spatial.Prefix
 {
-	/// <summary>
-	/// Based on {@link RecursivePrefixTreeFilter}.
-	/// </summary>
-	public class RecursivePrefixTreeStrategy : PrefixTreeStrategy
-	{
-		private int prefixGridScanLevel;
-
-		public RecursivePrefixTreeStrategy(SpatialPrefixTree grid, string fieldName)
-			: base(grid, fieldName)
-		{
-			prefixGridScanLevel = grid.GetMaxLevels() - 4;//TODO this default constant is dependent on the prefix grid size
-		}
-
-		public void SetPrefixGridScanLevel(int prefixGridScanLevel)
-		{
-			//TODO if negative then subtract from maxlevels
-			this.prefixGridScanLevel = prefixGridScanLevel;
-		}
-
-		public override Filter MakeFilter(SpatialArgs args)
-		{
-			var op = args.Operation;
+    /// <summary>
+    /// Based on {@link RecursivePrefixTreeFilter}.
+    /// </summary>
+    public class RecursivePrefixTreeStrategy : PrefixTreeStrategy
+    {
+        private int prefixGridScanLevel;
+
+        public RecursivePrefixTreeStrategy(SpatialPrefixTree grid, string fieldName)
+            : base(grid, fieldName)
+        {
+            prefixGridScanLevel = grid.GetMaxLevels() - 4;//TODO this default constant is dependent on the prefix grid size
+        }
+
+        public void SetPrefixGridScanLevel(int prefixGridScanLevel)
+        {
+            //TODO if negative then subtract from maxlevels
+            this.prefixGridScanLevel = prefixGridScanLevel;
+        }
+
+        public override Filter MakeFilter(SpatialArgs args)
+        {
+            var op = args.Operation;
             if (op != SpatialOperation.Intersects)
-				throw new UnsupportedSpatialOperation(op);
+                throw new UnsupportedSpatialOperation(op);
 
-			Shape shape = args.Shape;
+            Shape shape = args.Shape;
 
             int detailLevel = grid.GetLevelForDistance(args.ResolveDistErr(ctx, distErrPct));
 
-			return new RecursivePrefixTreeFilter(GetFieldName(), grid, shape, prefixGridScanLevel, detailLevel);
-		}
+            return new RecursivePrefixTreeFilter(GetFieldName(), grid, shape, prefixGridScanLevel, detailLevel);
+        }
 
-		public override string ToString()
-		{
-			return GetType().Name + "(prefixGridScanLevel:" + prefixGridScanLevel + ",SPG:(" + grid + "))";
-		}
-	}
+        public override string ToString()
+        {
+            return GetType().Name + "(prefixGridScanLevel:" + prefixGridScanLevel + ",SPG:(" + grid + "))";
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/62f018ab/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs b/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs
index a658a0b..84a074a 100644
--- a/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs
+++ b/src/contrib/Spatial/Prefix/TermQueryPrefixTreeStrategy.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.
@@ -25,32 +25,32 @@ using Spatial4n.Core.Shapes;
 
 namespace Lucene.Net.Spatial.Prefix
 {
-	/// <summary>
-	/// A basic implementation using a large {@link TermsFilter} of all the nodes from
-	/// {@link SpatialPrefixTree#getNodes(com.spatial4j.core.shape.Shape, int, boolean)}.
-	/// </summary>
-	public class TermQueryPrefixTreeStrategy : PrefixTreeStrategy
-	{
-		public TermQueryPrefixTreeStrategy(SpatialPrefixTree grid, string fieldName)
-			: base(grid, fieldName)
-		{
-		}
+    /// <summary>
+    /// A basic implementation using a large {@link TermsFilter} of all the nodes from
+    /// {@link SpatialPrefixTree#getNodes(com.spatial4j.core.shape.Shape, int, boolean)}.
+    /// </summary>
+    public class TermQueryPrefixTreeStrategy : PrefixTreeStrategy
+    {
+        public TermQueryPrefixTreeStrategy(SpatialPrefixTree grid, string fieldName)
+            : base(grid, fieldName)
+        {
+        }
 
-		public override Filter MakeFilter(SpatialArgs args)
-		{
-			SpatialOperation op = args.Operation;
+        public override Filter MakeFilter(SpatialArgs args)
+        {
+            SpatialOperation op = args.Operation;
             if (op != SpatialOperation.Intersects)
-				throw new UnsupportedSpatialOperation(op);
+                throw new UnsupportedSpatialOperation(op);
 
-			Shape shape = args.Shape;
+            Shape shape = args.Shape;
             int detailLevel = grid.GetLevelForDistance(args.ResolveDistErr(ctx, distErrPct));
-			var cells = grid.GetNodes(shape, detailLevel, false);
-			var filter = new TermsFilter();
-			foreach (Node cell in cells)
-			{
-				filter.AddTerm(new Term(GetFieldName(), cell.GetTokenString()));
-			}
-			return filter;
-		}
-	}
+            var cells = grid.GetNodes(shape, detailLevel, false);
+            var filter = new TermsFilter();
+            foreach (Node cell in cells)
+            {
+                filter.AddTerm(new Term(GetFieldName(), cell.GetTokenString()));
+            }
+            return filter;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/62f018ab/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs b/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs
index 27676e4..b05d7d2 100644
--- a/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs
+++ b/src/contrib/Spatial/Prefix/Tree/GeohashPrefixTree.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/62f018ab/src/contrib/Spatial/Prefix/Tree/Node.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Spatial/Prefix/Tree/Node.cs b/src/contrib/Spatial/Prefix/Tree/Node.cs
index 033bbb8..ce403b0 100644
--- a/src/contrib/Spatial/Prefix/Tree/Node.cs
+++ b/src/contrib/Spatial/Prefix/Tree/Node.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.
@@ -24,199 +24,199 @@ using Spatial4n.Core.Shapes;
 
 namespace Lucene.Net.Spatial.Prefix.Tree
 {
-	public abstract class Node : IComparable<Node>
-	{
-		public static byte LEAF_BYTE = (byte)'+';//NOTE: must sort before letters & numbers
-
-		// /*
-		//Holds a byte[] and/or String representation of the cell. Both are lazy constructed from the other.
-		//Neither contains the trailing leaf byte.
-		// */
-		//private byte[] bytes;
-		//private int b_off;
-		//private int b_len;
-
-		private String token;//this is the only part of equality
-
-		protected SpatialRelation shapeRel;//set in getSubCells(filter), and via setLeaf().
-		protected readonly SpatialPrefixTree spatialPrefixTree;
-
-		protected Node(SpatialPrefixTree spatialPrefixTree, String token)
-		{
-			this.spatialPrefixTree = spatialPrefixTree;
-			this.token = token;
-			if (token.Length > 0 && token[token.Length - 1] == (char)LEAF_BYTE)
-			{
-				this.token = token.Substring(0, token.Length - 1);
-				SetLeaf();
-			}
-
-			if (GetLevel() == 0)
-				GetShape();//ensure any lazy instantiation completes to make this threadsafe
-		}
-
-		public virtual void Reset(string newToken)
-		{
-			Debug.Assert(GetLevel() != 0);
-			this.token = newToken;
-			shapeRel = SpatialRelation.NULL_VALUE;
-			b_fixLeaf();
-		}
-
-		private void b_fixLeaf()
-		{
-			if (GetLevel() == spatialPrefixTree.GetMaxLevels())
-			{
-				SetLeaf();
-			}
-		}
-
-		public SpatialRelation GetShapeRel()
-		{
-			return shapeRel;
-		}
-
-		public bool IsLeaf()
-		{
-			return shapeRel == SpatialRelation.WITHIN;
-		}
-
-		public void SetLeaf()
-		{
-			Debug.Assert(GetLevel() != 0);
-			shapeRel = SpatialRelation.WITHIN;
-		}
-
-		/*
-		 * Note: doesn't contain a trailing leaf byte.
-		 */
-		public String GetTokenString()
-		{
-			if (token == null)
-				throw new InvalidOperationException("Somehow we got a null token");
-			return token;
-		}
-
-		///// <summary>
-		///// Note: doesn't contain a trailing leaf byte.
-		///// </summary>
-		///// <returns></returns>
-		//public byte[] GetTokenBytes()
-		//{
-		//    if (bytes != null)
-		//    {
-		//        if (b_off != 0 || b_len != bytes.Length)
-		//        {
-		//            throw new IllegalStateException("Not supported if byte[] needs to be recreated.");
-		//        }
-		//    }
-		//    else
-		//    {
-		//        bytes = token.GetBytes(SpatialPrefixTree.UTF8);
-		//        b_off = 0;
-		//        b_len = bytes.Length;
-		//    }
-		//    return bytes;
-		//}
-
-		public int GetLevel()
-		{
-			return token.Length;
-			//return token != null ? token.Length : b_len;
-		}
-
-		//TODO add getParent() and update some algorithms to use this?
-		//public Cell getParent();
-
-		/*
-		 * Like {@link #getSubCells()} but with the results filtered by a shape. If that shape is a {@link com.spatial4j.core.shape.Point} then it
-		 * must call {@link #getSubCell(com.spatial4j.core.shape.Point)};
-		 * Precondition: Never called when getLevel() == maxLevel.
-		 *
-		 * @param shapeFilter an optional filter for the returned cells.
-		 * @return A set of cells (no dups), sorted. Not Modifiable.
-		 */
-		public IList<Node> GetSubCells(Shape shapeFilter)
-		{
-			//Note: Higher-performing subclasses might override to consider the shape filter to generate fewer cells.
-			var point = shapeFilter as Point;
-			if (point != null)
-			{
+    public abstract class Node : IComparable<Node>
+    {
+        public static byte LEAF_BYTE = (byte)'+';//NOTE: must sort before letters & numbers
+
+        // /*
+        //Holds a byte[] and/or String representation of the cell. Both are lazy constructed from the other.
+        //Neither contains the trailing leaf byte.
+        // */
+        //private byte[] bytes;
+        //private int b_off;
+        //private int b_len;
+
+        private String token;//this is the only part of equality
+
+        protected SpatialRelation shapeRel;//set in getSubCells(filter), and via setLeaf().
+        protected readonly SpatialPrefixTree spatialPrefixTree;
+
+        protected Node(SpatialPrefixTree spatialPrefixTree, String token)
+        {
+            this.spatialPrefixTree = spatialPrefixTree;
+            this.token = token;
+            if (token.Length > 0 && token[token.Length - 1] == (char)LEAF_BYTE)
+            {
+                this.token = token.Substring(0, token.Length - 1);
+                SetLeaf();
+            }
+
+            if (GetLevel() == 0)
+                GetShape();//ensure any lazy instantiation completes to make this threadsafe
+        }
+
+        public virtual void Reset(string newToken)
+        {
+            Debug.Assert(GetLevel() != 0);
+            this.token = newToken;
+            shapeRel = SpatialRelation.NULL_VALUE;
+            b_fixLeaf();
+        }
+
+        private void b_fixLeaf()
+        {
+            if (GetLevel() == spatialPrefixTree.GetMaxLevels())
+            {
+                SetLeaf();
+            }
+        }
+
+        public SpatialRelation GetShapeRel()
+        {
+            return shapeRel;
+        }
+
+        public bool IsLeaf()
+        {
+            return shapeRel == SpatialRelation.WITHIN;
+        }
+
+        public void SetLeaf()
+        {
+            Debug.Assert(GetLevel() != 0);
+            shapeRel = SpatialRelation.WITHIN;
+        }
+
+        /*
+         * Note: doesn't contain a trailing leaf byte.
+         */
+        public String GetTokenString()
+        {
+            if (token == null)
+                throw new InvalidOperationException("Somehow we got a null token");
+            return token;
+        }
+
+        ///// <summary>
+        ///// Note: doesn't contain a trailing leaf byte.
+        ///// </summary>
+        ///// <returns></returns>
+        //public byte[] GetTokenBytes()
+        //{
+        //    if (bytes != null)
+        //    {
+        //        if (b_off != 0 || b_len != bytes.Length)
+        //        {
+        //            throw new IllegalStateException("Not supported if byte[] needs to be recreated.");
+        //        }
+        //    }
+        //    else
+        //    {
+        //        bytes = token.GetBytes(SpatialPrefixTree.UTF8);
+        //        b_off = 0;
+        //        b_len = bytes.Length;
+        //    }
+        //    return bytes;
+        //}
+
+        public int GetLevel()
+        {
+            return token.Length;
+            //return token != null ? token.Length : b_len;
+        }
+
+        //TODO add getParent() and update some algorithms to use this?
+        //public Cell getParent();
+
+        /*
+         * Like {@link #getSubCells()} but with the results filtered by a shape. If that shape is a {@link com.spatial4j.core.shape.Point} then it
+         * must call {@link #getSubCell(com.spatial4j.core.shape.Point)};
+         * Precondition: Never called when getLevel() == maxLevel.
+         *
+         * @param shapeFilter an optional filter for the returned cells.
+         * @return A set of cells (no dups), sorted. Not Modifiable.
+         */
+        public IList<Node> GetSubCells(Shape shapeFilter)
+        {
+            //Note: Higher-performing subclasses might override to consider the shape filter to generate fewer cells.
+            var point = shapeFilter as Point;
+            if (point != null)
+            {
 #if !NET35
-				return new ReadOnlyCollectionBuilder<Node>(new[] {GetSubCell(point)}).ToReadOnlyCollection();
+                return new ReadOnlyCollectionBuilder<Node>(new[] {GetSubCell(point)}).ToReadOnlyCollection();
 #else
                 return new List<Node>(new[]{GetSubCell(point)}).AsReadOnly();
 #endif
 
-			}
+            }
 
-			var cells = GetSubCells();
-			if (shapeFilter == null)
-			{
-				return cells;
-			}
-			var copy = new List<Node>(cells.Count);//copy since cells contractually isn't modifiable
-			foreach (var cell in cells)
-			{
+            var cells = GetSubCells();
+            if (shapeFilter == null)
+            {
+                return cells;
+            }
+            var copy = new List<Node>(cells.Count);//copy since cells contractually isn't modifiable
+            foreach (var cell in cells)
+            {
                 SpatialRelation rel = cell.GetShape().Relate(shapeFilter);
-				if (rel == SpatialRelation.DISJOINT)
-					continue;
-				cell.shapeRel = rel;
-				copy.Add(cell);
-			}
-			cells = copy;
-			return cells;
-		}
-
-		/*
-		 * Performant implementations are expected to implement this efficiently by considering the current
-		 * cell's boundary.
-		 * Precondition: Never called when getLevel() == maxLevel.
-		 * Precondition: this.getShape().relate(p) != DISJOINT.
-		 */
-		public abstract Node GetSubCell(Point p);
-
-		//TODO Cell getSubCell(byte b)
-
-		/*
-		 * Gets the cells at the next grid cell level that cover this cell.
-		 * Precondition: Never called when getLevel() == maxLevel.
-		 *
-		 * @return A set of cells (no dups), sorted. Not Modifiable.
-		 */
-		public abstract IList<Node> GetSubCells();
-
-		/*
-		 * {@link #getSubCells()}.size() -- usually a constant. Should be >=2
-		 */
-		public abstract int GetSubCellsSize();
-
-		public abstract Shape GetShape();
-
-		public virtual Point GetCenter()
-		{
-			return GetShape().GetCenter();
-		}
-
-
-		public int CompareTo(Node o)
-		{
-			return System.String.CompareOrdinal(GetTokenString(), o.GetTokenString());
-		}
-
-		public override bool Equals(object obj)
-		{
-			return !(obj == null || !(obj is Node)) && GetTokenString().Equals(((Node) obj).GetTokenString());
-		}
-
-		public override int GetHashCode()
-		{
-			return GetTokenString().GetHashCode();
-		}
-
-		public override string ToString()
-		{
-			return GetTokenString() + (IsLeaf() ? new string(new[] {(char) LEAF_BYTE}) : string.Empty);
-		}
-	}
+                if (rel == SpatialRelation.DISJOINT)
+                    continue;
+                cell.shapeRel = rel;
+                copy.Add(cell);
+            }
+            cells = copy;
+            return cells;
+        }
+
+        /*
+         * Performant implementations are expected to implement this efficiently by considering the current
+         * cell's boundary.
+         * Precondition: Never called when getLevel() == maxLevel.
+         * Precondition: this.getShape().relate(p) != DISJOINT.
+         */
+        public abstract Node GetSubCell(Point p);
+
+        //TODO Cell getSubCell(byte b)
+
+        /*
+         * Gets the cells at the next grid cell level that cover this cell.
+         * Precondition: Never called when getLevel() == maxLevel.
+         *
+         * @return A set of cells (no dups), sorted. Not Modifiable.
+         */
+        public abstract IList<Node> GetSubCells();
+
+        /*
+         * {@link #getSubCells()}.size() -- usually a constant. Should be >=2
+         */
+        public abstract int GetSubCellsSize();
+
+        public abstract Shape GetShape();
+
+        public virtual Point GetCenter()
+        {
+            return GetShape().GetCenter();
+        }
+
+
+        public int CompareTo(Node o)
+        {
+            return System.String.CompareOrdinal(GetTokenString(), o.GetTokenString());
+        }
+
+        public override bool Equals(object obj)
+        {
+            return !(obj == null || !(obj is Node)) && GetTokenString().Equals(((Node) obj).GetTokenString());
+        }
+
+        public override int GetHashCode()
+        {
+            return GetTokenString().GetHashCode();
+        }
+
+        public override string ToString()
+        {
+            return GetTokenString() + (IsLeaf() ? new string(new[] {(char) LEAF_BYTE}) : string.Empty);
+        }
+    }
 }