public override Filter MakeFilter(SpatialArgs args)
		{
			var op = args.Operation;
			if (!SpatialOperation.Is(op, SpatialOperation.IsWithin, SpatialOperation.Intersects, SpatialOperation.BBoxWithin, SpatialOperation.BBoxIntersects))
				throw new UnsupportedSpatialOperation(op);

			Shape shape = args.GetShape();

			int detailLevel = grid.GetMaxLevelForPrecision(shape, args.GetDistPrecision());

			return new RecursivePrefixTreeFilter(GetFieldName(), grid, shape, prefixGridScanLevel, detailLevel);
		}
		public override Filter MakeFilter(SpatialArgs args)
		{
			SpatialOperation op = args.Operation;
			if (
				!SpatialOperation.Is(op, SpatialOperation.IsWithin, SpatialOperation.Intersects, SpatialOperation.BBoxWithin,
				                     SpatialOperation.BBoxIntersects))
				throw new UnsupportedSpatialOperation(op);

			Shape shape = args.GetShape();
			int detailLevel = grid.GetMaxLevelForPrecision(shape, args.GetDistPrecision());
			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;
		}
		public override Query MakeQuery(SpatialArgs args)
		{
			// For starters, just limit the bbox
			var shape = args.GetShape();
			if (!(shape is Rectangle || shape is Circle))
				throw new InvalidShapeException("Only Rectangles and Circles are currently supported, found ["
					+ shape.GetType().Name + "]");//TODO

			Rectangle bbox = shape.GetBoundingBox();
			if (bbox.GetCrossesDateLine())
			{
				throw new InvalidOperationException("Crossing dateline not yet supported");
			}

			ValueSource valueSource = null;

			Query spatial = null;
			SpatialOperation op = args.Operation;

			if (SpatialOperation.Is(op,
				SpatialOperation.BBoxWithin,
				SpatialOperation.BBoxIntersects))
			{
				spatial = MakeWithin(bbox);
			}
			else if (SpatialOperation.Is(op,
			  SpatialOperation.Intersects,
			  SpatialOperation.IsWithin))
			{
				spatial = MakeWithin(bbox);
				var circle = args.GetShape() as Circle;
				if (circle != null)
				{
					// Make the ValueSource
					valueSource = MakeValueSource(args);

					var vsf = new ValueSourceFilter(
						new QueryWrapperFilter(spatial), valueSource, 0, circle.GetRadius());

					spatial = new FilteredQuery(new MatchAllDocsQuery(), vsf);
				}
			}
			else if (op == SpatialOperation.IsDisjointTo)
			{
				spatial = MakeDisjoint(bbox);
			}

			if (spatial == null)
			{
				throw new UnsupportedSpatialOperation(args.Operation);
			}

			if (valueSource != null)
			{
				valueSource = new CachingDoubleValueSource(valueSource);
			}
			else
			{
				valueSource = MakeValueSource(args);
			}
			Query spatialRankingQuery = new FunctionQuery(valueSource);
			var bq = new BooleanQuery();
			bq.Add(spatial, Occur.MUST);
			bq.Add(spatialRankingQuery, Occur.MUST);
			return bq;

		}
		public override ValueSource MakeValueSource(SpatialArgs args)
		{
			Point p = args.GetShape().GetCenter();
			return new DistanceValueSource(this, p, ctx.GetDistCalc());
		}
		public override Filter MakeFilter(SpatialArgs args)
		{
			var circle = args.GetShape() as Circle;
			if (circle != null)
			{
				if (SpatialOperation.Is(args.Operation,
					SpatialOperation.Intersects,
					SpatialOperation.IsWithin))
				{
					Query bbox = MakeWithin(circle.GetBoundingBox());

					// Make the ValueSource
					ValueSource valueSource = MakeValueSource(args);

					return new ValueSourceFilter(
						new QueryWrapperFilter(bbox), valueSource, 0, circle.GetRadius());
				}
			}
			return new QueryWrapperFilter(MakeQuery(args));
		}
		public ValueSource MakeValueSource(SpatialArgs args, DistanceCalculator calc)
		{
			var p = (PointPrefixTreeFieldCacheProvider)GetCacheProvider();
			Point point = args.GetShape().GetCenter();
			return new ShapeFieldCacheDistanceValueSource(point, calc, p);
		}