Index: contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java	(revision 833867)
+++ contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java	Wed Jan 20 14:35:46 CET 2010
@@ -31,8 +31,10 @@
 /** <p><font color="red"><b>NOTE:</b> This API is still in
  * flux and might change in incompatible ways in the next
  * release.</font>
+ *
+ * @deprecated This class has been replaced by DistanceFilter and GeoHashPointDecoder.  It will be removed.
  */
-
+@Deprecated
 public class GeoHashDistanceFilter extends DistanceFilter {
 
   /**
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/GeoHashPointDecoder.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/GeoHashPointDecoder.java	Wed Jan 20 15:06:23 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/GeoHashPointDecoder.java	Wed Jan 20 15:06:23 CET 2010
@@ -0,0 +1,65 @@
+/** 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.FieldCache;
+import org.apache.lucene.spatial.geohash.GeoHashUtils;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+
+/**
+ * PointDecoder which uses {@link org.apache.lucene.spatial.geohash.GeoHashUtils#decode(String)} to decode the point
+ * data for a document.
+ */
+public class GeoHashPointDecoder implements PointDecoder {
+
+  private final String geoHashField;
+
+  /**
+   * Creates a new GeoHashPointDecoder that decodes the data taken from the given field
+   *
+   * @param geoHashField Name of the field in documents where the encoded geohash data is
+   */
+  public GeoHashPointDecoder(String geoHashField) {
+    this.geoHashField = geoHashField;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public Point getPoint(int docId, IndexReader reader) throws IOException {
+    double[] coords = GeoHashUtils.decode(getGeoHash(docId, reader));
+    return new Point(coords[0], coords[1]);
+  }
+
+  // ================================================= Helper Methods ================================================
+
+  /**
+   * Retrieves the geohash for the document through the IndexReader
+   *
+   * @param docId ID of the document whose geohash is to be retrieved
+   * @param reader IndexReader through which the hash can be retrieved
+   * @return Geohash for the document
+   * @throws IOException Can be thrown while interacting with the index
+   */
+  String getGeoHash(int docId, IndexReader reader) throws IOException {
+    FieldCache.StringIndex stringIndex = FieldCache.DEFAULT.getStringIndex(reader, geoHashField);
+    return stringIndex.lookup[stringIndex.order[docId]];
+  }
+}
Index: contrib/spatial/src/test/org/apache/lucene/spatial/distance/GeoHashPointDecoderTest.java
===================================================================
--- contrib/spatial/src/test/org/apache/lucene/spatial/distance/GeoHashPointDecoderTest.java	Wed Jan 20 15:08:50 CET 2010
+++ contrib/spatial/src/test/org/apache/lucene/spatial/distance/GeoHashPointDecoderTest.java	Wed Jan 20 15:08:50 CET 2010
@@ -0,0 +1,49 @@
+/** 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import junit.framework.TestCase;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+
+/**
+ * Tests for {@link org.apache.lucene.spatial.distance.GeoHashPointDecoder}
+ */
+public class GeoHashPointDecoderTest extends TestCase {
+
+  /**
+   * Pass condition: The geohash for the document is retrieved and decoded into a Point
+   *
+   * @throws IOException Can be thrown while interacting with the index
+   */
+  public void testGetPoint() throws IOException {
+    GeoHashPointDecoder pointDecoder = new GeoHashPointDecoder("geohash") {
+
+      @Override
+      String getGeoHash(int docId, IndexReader reader) throws IOException {
+        return "ezs42e44yx96";
+      }
+    };
+
+    Point point = pointDecoder.getPoint(0, null);
+
+    assertEquals(42.6, point.getX(), 0.00001D);
+    assertEquals(-5.6, point.getY(), 0.00001D);
+  }
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/SimpleDocumentDistanceSource.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/SimpleDocumentDistanceSource.java	Wed Jan 20 15:08:44 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/SimpleDocumentDistanceSource.java	Wed Jan 20 15:08:44 CET 2010
@@ -0,0 +1,53 @@
+/** 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.spatial.geometry.DistanceUnits;
+import org.apache.lucene.spatial.geometry.GeoDistanceCalculator;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+
+/**
+ * Simple implementation of {@link DocumentDistanceSource} which calculates the distance eachtime without any caching.
+ */
+public class SimpleDocumentDistanceSource implements DocumentDistanceSource {
+
+  private final PointDecoder pointDecoder;
+  private final GeoDistanceCalculator distanceCalculator;
+
+  /**
+   * Creates a new SimpleDocumentDistanceSource which uses the given PointDecoder to retrieve the Points for documents,
+   * and the given GeoDistanceCalculator to calculate the distance
+   *
+   * @param pointDecoder PointDecoder to use to retrieve Points for documents
+   * @param distanceCalculator GeoDistanceCalculator to use to calculate the actual distances
+   */
+  public SimpleDocumentDistanceSource(PointDecoder pointDecoder, GeoDistanceCalculator distanceCalculator) {
+    this.pointDecoder = pointDecoder;
+    this.distanceCalculator = distanceCalculator;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public double getDocumentDistance(int docId, Point src, IndexReader indexReader, DistanceUnits units) throws IOException {
+    Point docPoint = pointDecoder.getPoint(docId, indexReader);
+    return distanceCalculator.calculate(src.getX(), src.getY(), docPoint.getX(), docPoint.getY(), units);
+  }
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/NoOpDistanceFilter.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/NoOpDistanceFilter.java	Sun Jan 17 15:37:16 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/NoOpDistanceFilter.java	Sun Jan 17 15:37:16 CET 2010
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+
+import java.io.IOException;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Implementation of {@link DistanceFilter} that does no actual filtering.  This means that there can always be a DistanceFilter
+ * instantiated, but that the actual process of filtering documents by their distance, which is a computationally expensive
+ * process, doesn't always have to occur.
+ *
+ * <p><font color="red"><b>NOTE:</b> This API is still in flux and might change in incompatible ways in the next release.</font>
+ */
+public class NoOpDistanceFilter implements DistanceFilter {
+
+  /**
+   * Executes no filtering.  Simply returns the given BitSet
+   * <p/>
+   * {@inheritDoc}
+   */
+  public BitSet bits(IndexReader reader, BitSet bits) throws IOException {
+    return bits;
+  }
+}
Index: contrib/spatial/src/test/org/apache/lucene/spatial/distance/TestThreadedDistanceFilter.java
===================================================================
--- contrib/spatial/src/test/org/apache/lucene/spatial/distance/TestThreadedDistanceFilter.java	Wed Jan 20 15:05:00 CET 2010
+++ contrib/spatial/src/test/org/apache/lucene/spatial/distance/TestThreadedDistanceFilter.java	Wed Jan 20 15:05:00 CET 2010
@@ -0,0 +1,264 @@
+/**
+ * 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import junit.framework.TestCase;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.spatial.geometry.ArcGeoDistanceCalculator;
+import org.apache.lucene.spatial.geometry.DistanceUnits;
+import org.apache.lucene.spatial.geometry.GeoDistanceCalculator;
+import org.apache.lucene.spatial.geometry.Point;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
+import org.apache.lucene.util.Version;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * Tests for {@link TestThreadedDistanceFilter}
+ */
+public class TestThreadedDistanceFilter extends TestCase {
+
+  private final List<Point> testPoints = Arrays.asList(new Point(4.53, 30.61), new Point(4.51, 31.01), new Point(5.69, 40.89));
+
+  private final PointDecoder pointDecoder = new PointDecoder() {
+
+    public Point getPoint(int docId, IndexReader reader) throws IOException {
+      return testPoints.get(docId);
+    }
+  };
+
+  private Directory directory;
+
+  /**
+   * Creates a new in-memory Directory containing an index with a document for each point in {@link #testPoints}
+   *
+   * @throws IOException Can be thrown creating the index
+   */
+  public void setUp() throws IOException {
+    directory = new RAMDirectory();
+    IndexWriter indexWriter = new IndexWriter(directory, new StandardAnalyzer(Version.LUCENE_CURRENT), IndexWriter.MaxFieldLength.UNLIMITED);
+    for (int i = 0; i < testPoints.size(); i++) {
+      addDocument(indexWriter, i);
+    }
+    indexWriter.commit();
+    indexWriter.close();
+  }
+
+  /**
+   * Closes the Directory
+   *
+   * @throws IOException Can be thrown closing the Directory
+   */
+  public void tearDown() throws IOException {
+    directory.close();
+  }
+
+  /**
+   * Adds a Document with a single field "id" with the given id as its value
+   *
+   * @param indexWriter IndexWriter to write the document too
+   * @param id ID that the document will have
+   * @throws IOException Can be thrown while writing document to the index
+   */
+  private void addDocument(IndexWriter indexWriter, int id) throws IOException {
+    Document document = new Document();
+    document.add(new Field("id", String.valueOf(id), Field.Store.YES, Field.Index.ANALYZED));
+    indexWriter.addDocument(document);
+  }
+
+  /**
+   * Pass condition: The latitude/longitude values have to be passed to the GeoDistanceCalculator in the correct order
+   *
+   * @throws IOException Can be thrown reading from the index
+   */
+  public void testGeoCalculation_correctArgumentPassing() throws IOException {
+    StubGeoDistanceCalculator distanceCalculator = new StubGeoDistanceCalculator();
+    ExecutorService executorService = Executors.newFixedThreadPool(1);
+
+    DocumentDistanceSource distanceSource = new SimpleDocumentDistanceSource(pointDecoder, distanceCalculator);
+
+    ThreadedDistanceFilter filter =
+        new ThreadedDistanceFilter(new Point(4.51, 31.01), 10, DistanceUnits.KILOMETERS, distanceSource, executorService, 1);
+
+    IndexReader indexReader = IndexReader.open(directory);
+    BitSet bitSet = new BitSet(1);
+    bitSet.set(0);
+    filter.bits(indexReader, bitSet);
+
+    assertEquals(4.51, distanceCalculator.getSourceLatitude(), 0);
+    assertEquals(31.01, distanceCalculator.getSourceLongitude(), 0);
+    assertEquals(4.53, distanceCalculator.getTargetLatitude(), 0);
+    assertEquals(30.61, distanceCalculator.getTargetLongitude(), 0);
+
+    indexReader.close();
+  }
+
+  /**
+   * Pass condition: 2 threads with the correct start and end indexes are created based on the BitSet given in the method
+   * call, and the number of threads that were requested.
+   *
+   * @throws java.io.IOException Can be thrown while reading from the index
+   */
+  public void testBits() throws IOException {
+    ExecutorService executorService = new ThreadPoolExecutor(2, 6, 8, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
+    DocumentDistanceSource distanceSource = new SimpleDocumentDistanceSource(pointDecoder, new ArcGeoDistanceCalculator());
+    
+    BitSet bitSet = new BitSet(13);
+    bitSet.set(2, 6);
+    bitSet.set(8, 9);
+    bitSet.set(11);
+
+    final List<IterateCallInfo> infoList = Collections.synchronizedList(new ArrayList<IterateCallInfo>());
+    ThreadedDistanceFilter distanceFilter = new ThreadedDistanceFilter(new Point(4.52, 30.81), 30, DistanceUnits.MILES, distanceSource, executorService, 2) {
+
+      @Override
+      protected IterationResult iterate(BitSet originalBitSet, int start, int end, int size, IndexReader reader) {
+        infoList.add(new IterateCallInfo(start, end, size));
+        return new IterationResult(new BitSet());
+      }
+    };
+
+    IndexReader indexReader = IndexReader.open(directory);
+
+    distanceFilter.bits(indexReader, bitSet);
+
+    assertEquals(2, infoList.size());
+
+    Collections.sort(infoList, new Comparator<IterateCallInfo>() {
+      public int compare(IterateCallInfo info1, IterateCallInfo info2) {
+        return info1.getStart() - info2.getStart();
+      }
+    });
+
+    IterateCallInfo callInfo = infoList.get(0);
+    assertEquals(0, callInfo.getStart());
+    assertEquals(6, callInfo.getEnd());
+    assertEquals(6, callInfo.getSize());
+
+    callInfo = infoList.get(1);
+    assertEquals(6, callInfo.getStart());
+    assertEquals(12, callInfo.getEnd());
+    assertEquals(6, callInfo.getSize());
+
+    indexReader.close();
+  }
+
+  /**
+   * Pass condition: Of the 3 documents with points, 1 is outside of the radius and should be filtered out, 1 has been
+   * deleted so it should also be filtered out, leaving just 1 that passes the filter.  Its distance should be recorded
+   * in the calculated distances of the filter
+   *
+   * @throws IOException Can be thrown when interactin with the index
+   */
+  public void testIterate() throws IOException {
+    IndexReader indexReader = IndexReader.open(directory, false);
+    indexReader.deleteDocument(1);
+
+    BitSet bitSet = new BitSet(2);
+    bitSet.set(0);
+    bitSet.set(1);
+    bitSet.set(2);
+
+    MapCachingDocumentDistanceSource distanceSource = new MapCachingDocumentDistanceSource(new SimpleDocumentDistanceSource(pointDecoder, new ArcGeoDistanceCalculator()));
+
+    ThreadedDistanceFilter distanceFilter = new ThreadedDistanceFilter(new Point(4.52, 30.81), 30, DistanceUnits.MILES, distanceSource, null, 0);
+
+    ThreadedDistanceFilter.IterationResult result = distanceFilter.iterate(bitSet, 0, 3, 3, indexReader);
+
+    assertNotNull(result);
+
+    BitSet resultingBitSet = result.getBitSet();
+    assertNotNull(resultingBitSet);
+    assertTrue(resultingBitSet.get(0));
+    assertFalse(resultingBitSet.get(1));
+    assertFalse(resultingBitSet.get(2));
+
+    assertEquals(2, distanceSource.getCachedDistances().size());
+
+    indexReader.close();
+  }
+
+  // ================================================= Inner Classes =================================================
+
+  private static class IterateCallInfo {
+
+    private final int start;
+    private final int end;
+    private final int size;
+
+    private IterateCallInfo(int start, int end, int size) {
+      this.start = start;
+      this.end = end;
+      this.size = size;
+    }
+
+    public int getStart() {
+      return start;
+    }
+
+    public int getEnd() {
+      return end;
+    }
+
+    public int getSize() {
+      return size;
+    }
+  }
+
+  /**
+   * Dummy implementation. Used for unit test to assure that the given arguments to a distance calculator are given correctly .
+   */
+  class StubGeoDistanceCalculator implements GeoDistanceCalculator {
+
+    private double sourceLatitude;
+    private double sourceLongitude;
+    private double targetLatitude;
+    private double targetLongitude;
+
+    public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnits unit) {
+      this.sourceLatitude = sourceLatitude;
+      this.sourceLongitude = sourceLongitude;
+      this.targetLatitude = targetLatitude;
+      this.targetLongitude = targetLongitude;
+      return 0.0;
+    }
+
+    public double getSourceLatitude() {
+      return sourceLatitude;
+    }
+
+    public double getSourceLongitude() {
+      return sourceLongitude;
+    }
+
+    public double getTargetLatitude() {
+      return targetLatitude;
+    }
+
+    public double getTargetLongitude() {
+      return targetLongitude;
+    }
+  }
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/LatLngPointDecoder.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/LatLngPointDecoder.java	Wed Jan 20 15:08:24 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/LatLngPointDecoder.java	Wed Jan 20 15:08:24 CET 2010
@@ -0,0 +1,66 @@
+/** 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.FieldCache;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+
+/**
+ * PointDecoder that uses latitude and longitude data that is stored in two separate fields.
+ */
+public class LatLngPointDecoder implements PointDecoder {
+
+  private final String latField;
+  private final String lngField;
+
+  /**
+   * Creates a new LatLngPointDecoder that uses the data found in the given latitude and longitude fields
+   *
+   * @param latField Name of the field in documents containing laitutde data
+   * @param lngField Name of the field in documents containing longitude data
+   */
+  public LatLngPointDecoder(String latField, String lngField) {
+    this.latField = latField;
+    this.lngField = lngField;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public Point getPoint(int docId, IndexReader reader) throws IOException {
+    double[] latValues = getFieldValues(latField, reader);
+    double[] lngValues = getFieldValues(lngField, reader);
+    return new Point(latValues[docId], lngValues[docId]);
+  }
+
+  // ================================================= Helper Methods ================================================
+
+  /**
+   * Gets the values for the given field from the IndexReader
+   *
+   * @param field Field whose values are to be retrieved
+   * @param indexReader IndexReader from where the values are to be retrieved
+   * @return Values for the field
+   * @throws IOException Can be thrown while interacting with the index
+   */
+  double[] getFieldValues(String field, IndexReader indexReader) throws IOException {
+    return FieldCache.DEFAULT.getDoubles(indexReader, field, FieldCache.NUMERIC_UTILS_DOUBLE_PARSER);
+  }
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/PointDecoder.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/PointDecoder.java	Wed Jan 20 15:08:44 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/PointDecoder.java	Wed Jan 20 15:08:44 CET 2010
@@ -0,0 +1,38 @@
+/** 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+
+/**
+ * PointDecoders decode the representation of a point for a document into instances of {@link org.apache.lucene.spatial.geometry.Point}
+ */
+public interface PointDecoder {
+
+  /**
+   * Retrieves the Point for the document with the given ID
+   *
+   * @param docId ID of the document whose point is to be retrieved
+   * @param reader IndexReader for communicating with the index
+   * @return Point representation of the decoded data
+   * @throws IOException Can be thrown while interacting with the index
+   */
+  Point getPoint(int docId, IndexReader reader) throws IOException;
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/DistanceFilter.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/DistanceFilter.java	Sun Jan 17 15:33:25 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/DistanceFilter.java	Sun Jan 17 15:33:25 CET 2010
@@ -0,0 +1,44 @@
+/** 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+
+import java.io.IOException;
+import java.util.BitSet;
+import java.util.Map;
+
+/**
+ * DistanceFilter is responsible for filtering out documents from an existing BitSet, based on their calculated distance
+ * from the central point.  Because the costing of calculating distances for documents is relatively high, this filter
+ * uses an existing BitSet, which will have been created another filter previously.  As such, this is technically not
+ * a Lucene Filter.
+ *
+ * <p><font color="red"><b>NOTE:</b> This API is still in flux and might change in incompatible ways in the next release.</font>
+ */
+public interface DistanceFilter {
+
+  /**
+   * Filters the documents from the given IndexReader who have bits set in the given BitSet.
+   *
+   * @param reader IndexReader from where the documents will be read from
+   * @param bits BitSet containing bits indicating which documents should be considered to be filtered out
+   * @return BitSet with bits set representing those documents that passed the filter
+   * @throws java.io.IOException Can be thrown while reading from the IndexReader
+   */
+  BitSet bits(IndexReader reader, BitSet bits) throws IOException;
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/MapCachingDocumentDistanceSource.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/MapCachingDocumentDistanceSource.java	Wed Jan 20 15:08:29 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/MapCachingDocumentDistanceSource.java	Wed Jan 20 15:08:29 CET 2010
@@ -0,0 +1,69 @@
+/** 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.spatial.geometry.DistanceUnits;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implementation of {@link DocumentDistanceSource} which caches calculated distances in a Map.  Note, the caching does
+ * not take into account the IndexReader, nor does it apply any multi-thread synchronisation.
+ */
+public class MapCachingDocumentDistanceSource implements DocumentDistanceSource {
+
+  private final DocumentDistanceSource source;
+  private final Map<Integer, Double> cachedDistances = new HashMap<Integer, Double>();
+
+  /**
+   * Creates a new MapCachingDocumentDistanceSource that caches distances from the given DocumentDistanceSource
+   *
+   * @param source DocumentDistanceSource whose calculated distances will be cached
+   */
+  public MapCachingDocumentDistanceSource(DocumentDistanceSource source) {
+    this.source = source;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public double getDocumentDistance(int docId, Point src, IndexReader indexReader, DistanceUnits units) throws IOException {
+    Double cachedDistance = cachedDistances.get(docId);
+    if (cachedDistance != null) {
+      return cachedDistance;
+    }
+    
+    double calculatedDistance = source.getDocumentDistance(docId, src, indexReader, units);
+    cachedDistances.put(docId, calculatedDistance);
+    return calculatedDistance;
+  }
+
+  // ================================================= Getters / Setters =============================================
+
+  /**
+   * Returns the cached distances
+   *
+   * @return Cached distances
+   */
+  public Map<Integer, Double> getCachedDistances() {
+    return cachedDistances;
+  }
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/ThreadedDistanceFilter.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/ThreadedDistanceFilter.java	Sun Jan 17 15:35:42 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/ThreadedDistanceFilter.java	Sun Jan 17 15:35:42 CET 2010
@@ -0,0 +1,175 @@
+/**
+ * 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.spatial.geometry.DistanceUnits;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+/**
+ * Implementation of {@link DistanceFilter} that uses multiple threads to iterate in parallel, over the BitSet to be filtered.
+ * <p/>
+ * To manage the threads, an ExecutorService is used, which allows users of this class to have fine grained control over
+ * how many threads should be created, and what to do when there isn't any threads left in the pool.
+ *
+ * <p><font color="red"><b>NOTE:</b> This API is still in flux and might change in incompatible ways in the next release.</font>
+ */
+public class ThreadedDistanceFilter implements DistanceFilter {
+
+  private final Point centralPoint;
+  private final double radius;
+  private final DistanceUnits unit;
+  private final DocumentDistanceSource documentDistanceSource;
+
+  private final ExecutorService executorService;
+  private final int threadCount;
+
+  /**
+   * Creates a new ThreadedDistanceFilter that will filter out documents that are outside of the given radius of the
+   * central point defined by the given latitude and longitude
+   *
+   * @param centralPoint Point at the centre of the search
+   * @param radius Radius that documents must be within from the central point to pass the filter
+   * @param unit Unit of distance the radius is in
+   * @param distanceSource DocumentDistanceSource from where the distances for documents from the central point, will be
+   *                       retrieved from
+   * @param executorService ExecutorService which will manage the execution of the threads
+   * @param threadCount Number of threads that the filter should try to split its work across
+   */
+  public ThreadedDistanceFilter(
+      Point centralPoint,
+      double radius,
+      DistanceUnits unit,
+      DocumentDistanceSource distanceSource,
+      ExecutorService executorService,
+      int threadCount) {
+    this.centralPoint = centralPoint;
+    this.radius = radius;
+    this.unit = unit;
+    this.documentDistanceSource = distanceSource;
+    this.executorService = executorService;
+    this.threadCount = threadCount;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public BitSet bits(final IndexReader reader, final BitSet bits) throws IOException {
+    int maxLength = bits.length();
+    int threadSize = maxLength / threadCount;
+    List<Callable<IterationResult>> tasks = new ArrayList<Callable<IterationResult>>();
+
+    for (int i = 0; i < threadCount; i++) {
+      final int start = i * threadSize;
+      // if the last batch of documents has been reached, then maxLength should be end
+      final int end = (i == threadCount - 1) ? maxLength : Math.min((i + 1) * threadSize, maxLength);
+      tasks.add(new Callable<IterationResult>() {
+        public IterationResult call() throws Exception {
+          return iterate(bits, start, end, end - start, reader);
+        }
+      });
+    }
+
+    BitSet result = new BitSet(bits.cardinality());
+
+    try {
+      List<Future<IterationResult>> results = executorService.invokeAll(tasks);
+      for (Future<IterationResult> resultFuture : results) {
+        IterationResult iterationResult = resultFuture.get();
+        result.or(iterationResult.getBitSet());
+      }
+    } catch (InterruptedException ie) {
+      throw new RuntimeException("InterruptedException thrown while executing tasks", ie);
+    } catch (ExecutionException ee) {
+      throw new RuntimeException("ExecutionException thrown while retrieving results of tasks", ee);
+    }
+
+    return result;
+  }
+
+  // ================================================ Helper Methods =================================================
+
+  /**
+   * Iterates over the set bits in the given BitSet from the given start to end range, calculating the distance of the
+   * documents and determining which are within the distance radius of the central point.
+   *
+   * @param originalBitSet BitSet which has bits set identifying which documents should be checked to see if their
+   *        distance falls within the radius
+   * @param start Index in the BitSet that the method will start at
+   * @param end Index in the BitSet that the method will stop at
+   * @param size Size the the resulting BitSet should be created at (most likely end - start)
+   * @param reader IndexReader for checking if the document has been deleted
+   * @return IterationResult containing all the results of the method.
+   * @throws IOException Can be thrown while interacting with the index
+   */
+  protected IterationResult iterate(BitSet originalBitSet, int start, int end, int size, IndexReader reader) throws IOException {
+    BitSet bitSet = new BitSet(size);
+
+    int docId = originalBitSet.nextSetBit(start);
+    while (docId != -1 && docId < end) {
+      if (reader.isDeleted(docId)) {
+        docId = originalBitSet.nextSetBit(docId + 1);
+        continue;
+      }
+
+      double distance = documentDistanceSource.getDocumentDistance(docId, centralPoint, reader, unit);
+      if (distance < radius) {
+        bitSet.set(docId);
+      }
+
+      docId = originalBitSet.nextSetBit(docId + 1);
+    }
+    return new IterationResult(bitSet);
+  }
+
+  // ================================================= Inner Classes =================================================
+
+  /**
+   * Wrapper of the results from {@link ThreadedDistanceFilter#iterate(BitSet, int, int, int, IndexReader)}.
+   * This allows the method to operate in almost total isolation in separate threads.
+   */
+  protected class IterationResult {
+
+    private BitSet bitSet;
+
+    /**
+     * Creates a new IterationResult that wraps the given BitSet
+     *
+     * @param bitSet BitSet to wrap
+     */
+    public IterationResult(BitSet bitSet) {
+      this.bitSet = bitSet;
+    }
+
+    /**
+     * Returns the wrapped BitSet
+     *
+     * @return Wrapped BitSet
+     */
+    public BitSet getBitSet() {
+      return bitSet;
+    }
+  }
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java	(revision 833867)
+++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java	Fri Dec 18 14:53:45 CET 2009
@@ -29,7 +29,10 @@
  * <p><font color="red"><b>NOTE:</b> This API is still in
  * flux and might change in incompatible ways in the next
  * release.</font>
+ *
+ * @deprecated This class has been made replaced by DistanceFilter and LatLngLocationDataSetFactory.  It will be removed.  
  */
+@Deprecated
 public class LatLongDistanceFilter extends DistanceFilter {
 
   /**
Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java	(revision 833867)
+++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java	Fri Dec 18 14:53:40 CET 2009
@@ -29,7 +29,10 @@
  * <p><font color="red"><b>NOTE:</b> This API is still in
  * flux and might change in incompatible ways in the next
  * release.</font>
+ *
+ * @deprecated This class has been replaced by DistanceFilter and its implementations.  It will be removed.
  */
+@Deprecated
 public abstract class DistanceFilter extends Filter {
 
   final protected Filter startingFilter;
Index: contrib/spatial/src/test/org/apache/lucene/spatial/distance/LatLngPointDecoderTest.java
===================================================================
--- contrib/spatial/src/test/org/apache/lucene/spatial/distance/LatLngPointDecoderTest.java	Wed Jan 20 15:08:54 CET 2010
+++ contrib/spatial/src/test/org/apache/lucene/spatial/distance/LatLngPointDecoderTest.java	Wed Jan 20 15:08:54 CET 2010
@@ -0,0 +1,55 @@
+/** 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.
+ */
+
+package org.apache.lucene.spatial.distance;
+
+import junit.framework.TestCase;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+
+/**
+ * Tests for {@link org.apache.lucene.spatial.distance.LatLngPointDecoder}
+ */
+public class LatLngPointDecoderTest extends TestCase {
+
+  /**
+   * Pass condition: The latitude and longitude for document 0 is correctly decoded from the lat and lng fields
+   * 
+   * @throws IOException Can be thrown while interacting with the index
+   */
+  public void testGetPoint() throws IOException {
+    LatLngPointDecoder pointDecoder = new LatLngPointDecoder("lat", "lng") {
+      
+      @Override
+      double[] getFieldValues(String field, IndexReader indexReader) {
+        if ("lat".equals(field)) {
+          return new double[]{40.3, 54.2};
+        } else if ("lng".equals(field)) {
+          return new double[]{3.21, 9.65};
+        } else {
+          throw new IllegalArgumentException("Unexpected field name: " + field);
+        }
+      }
+    };
+
+    Point point = pointDecoder.getPoint(0, null);
+
+    assertEquals(40.3, point.getX(), 0D);
+    assertEquals(3.21, point.getY(), 0D);
+  }
+}
Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/DocumentDistanceSource.java
===================================================================
--- contrib/spatial/src/java/org/apache/lucene/spatial/distance/DocumentDistanceSource.java	Wed Jan 20 15:05:37 CET 2010
+++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/DocumentDistanceSource.java	Wed Jan 20 15:05:37 CET 2010
@@ -0,0 +1,25 @@
+package org.apache.lucene.spatial.distance;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.spatial.geometry.DistanceUnits;
+import org.apache.lucene.spatial.geometry.Point;
+
+import java.io.IOException;
+
+/**
+ * Single access point for anything wishing to retrieve the distance a document is from a point.
+ */
+public interface DocumentDistanceSource {
+
+  /**
+   * Retrieves the distance the document with the given id is from the given Point.
+   *
+   * @param docId ID of the document whose distance is to be retrieved
+   * @param src Point from where the distance to the document is to be calculated
+   * @param indexReader IndexReader for interacting with the index
+   * @param units DistanceUnits that the distance should be returned in
+   * @return Distance the document is from the point in the defined units
+   * @throws IOException Can be thrown while interacting with the index
+   */
+  double getDocumentDistance(int docId, Point src, IndexReader indexReader, DistanceUnits units) throws IOException;
+}
