You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ds...@apache.org on 2012/02/20 23:45:37 UTC

svn commit: r1291499 [5/12] - in /lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/lucene/ src/main/java/org/apache/lucene/s...

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/StrategyTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/StrategyTestCase.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/StrategyTestCase.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/StrategyTestCase.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,150 @@
+/*
+ * 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;
+
+
+import junit.framework.Assert;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.io.sample.SampleData;
+import org.apache.lucene.spatial.base.io.sample.SampleDataReader;
+import org.apache.lucene.spatial.base.query.SpatialArgsParser;
+import org.apache.lucene.spatial.base.shape.Shape;
+import org.apache.lucene.spatial.strategy.SpatialFieldInfo;
+import org.apache.lucene.spatial.strategy.SpatialStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+public abstract class StrategyTestCase<T extends SpatialFieldInfo> extends SpatialTestCase {
+
+  public static final String DATA_STATES_POLY = "states-poly.txt";
+  public static final String DATA_STATES_BBOX = "states-bbox.txt";
+  public static final String DATA_COUNTRIES_POLY = "countries-poly.txt";
+  public static final String DATA_COUNTRIES_BBOX = "countries-bbox.txt";
+  public static final String DATA_WORLD_CITIES_POINTS = "world-cities-points.txt";
+
+  public static final String QTEST_States_IsWithin_BBox   = "states-IsWithin-BBox.txt";
+  public static final String QTEST_States_Intersects_BBox = "states-Intersects-BBox.txt";
+
+  public static final String QTEST_Cities_IsWithin_BBox = "cities-IsWithin-BBox.txt";
+
+  protected final Logger log = LoggerFactory.getLogger(getClass());
+
+  protected final SpatialArgsParser argsParser = new SpatialArgsParser();
+
+  protected SpatialStrategy<T> strategy;
+  protected SpatialContext ctx;
+  protected T fieldInfo;
+  protected boolean storeShape = true;
+
+  protected void executeQueries(SpatialMatchConcern concern, String... testQueryFile) throws IOException {
+    log.info("testing queried for strategy "+strategy);
+    for( String path : testQueryFile ) {
+      Iterator<SpatialTestQuery> testQueryIterator = getTestQueries(path, ctx);
+      runTestQueries(testQueryIterator, concern);
+    }
+  }
+
+  protected void getAddAndVerifyIndexedDocuments(String testDataFile) throws IOException {
+    List<Document> testDocuments = getDocuments(testDataFile);
+    addDocumentsAndCommit(testDocuments);
+    verifyDocumentsIndexed(testDocuments.size());
+  }
+
+  protected List<Document> getDocuments(String testDataFile) throws IOException {
+    Iterator<SampleData> sampleData = getSampleData(testDataFile);
+    List<Document> documents = new ArrayList<Document>();
+    while (sampleData.hasNext()) {
+      SampleData data = sampleData.next();
+      Document document = new Document();
+      document.add(new Field("id", data.id, StringField.TYPE_STORED));
+      document.add(new Field("name", data.name, StringField.TYPE_STORED));
+      Shape shape = ctx.readShape(data.shape);
+      for (IndexableField f : strategy.createFields(fieldInfo, shape, true, storeShape)) {
+        if( f != null ) { // null if incompatibleGeometry && ignore
+          document.add(f);
+        }
+      }
+      documents.add(document);
+    }
+    return documents;
+  }
+
+  protected Iterator<SampleData> getSampleData(String testDataFile) throws IOException {
+    return new SampleDataReader(
+        getClass().getClassLoader().getResourceAsStream("data/"+testDataFile) );
+  }
+
+  protected Iterator<SpatialTestQuery> getTestQueries(String testQueryFile, SpatialContext ctx) throws IOException {
+    InputStream in = getClass().getClassLoader().getResourceAsStream(testQueryFile);
+    return SpatialTestQuery.getTestQueries(
+        argsParser, ctx, testQueryFile, in );
+  }
+
+  public void runTestQueries(
+      Iterator<SpatialTestQuery> queries,
+      SpatialMatchConcern concern) {
+    while (queries.hasNext()) {
+      SpatialTestQuery q = queries.next();
+
+      String msg = q.line; //"Query: " + q.args.toString(ctx);
+      SearchResults got = executeQuery(strategy.makeQuery(q.args, fieldInfo), 100);
+      if (concern.orderIsImportant) {
+        Iterator<String> ids = q.ids.iterator();
+        for (SearchResult r : got.results) {
+          String id = r.document.get("id");
+          Assert.assertEquals( "out of order: " + msg, ids.next(), id);
+        }
+        if (ids.hasNext()) {
+          Assert.fail(msg + " :: expect more results then we got: " + ids.next());
+        }
+      } else {
+        // We are looking at how the results overlap
+        if( concern.resultsAreSuperset ) {
+          Set<String> found = new HashSet<String>();
+          for (SearchResult r : got.results) {
+            found.add(r.document.get("id"));
+          }
+          for( String s : q.ids ) {
+            if( !found.contains( s ) ) {
+              Assert.fail( "Results are mising id: "+s + " :: " + found );
+            }
+          }
+        }
+        else {
+          List<String> found = new ArrayList<String>();
+          for (SearchResult r : got.results) {
+            found.add(r.document.get("id"));
+          }
+
+          // sort both so that the order is not important
+          Collections.sort(q.ids);
+          Collections.sort(found);
+          Assert.assertEquals(msg, q.ids.toString(), found.toString());
+        }
+      }
+    }
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/TestTestFramework.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/TestTestFramework.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/TestTestFramework.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/TestTestFramework.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.query.SpatialArgsParser;
+import org.apache.lucene.spatial.base.query.SpatialOperation;
+import org.apache.lucene.spatial.base.shape.Rectangle;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * Make sure we are reading the tests as expected
+ */
+public class TestTestFramework {
+
+  @Test
+  public void testQueries() throws IOException {
+    String name = StrategyTestCase.QTEST_Cities_IsWithin_BBox;
+
+    InputStream in = getClass().getClassLoader().getResourceAsStream(name);
+    SpatialContext ctx = SimpleSpatialContext.GEO_KM;
+    Iterator<SpatialTestQuery> iter = SpatialTestQuery.getTestQueries(
+        new SpatialArgsParser(), ctx, name, in );
+    List<SpatialTestQuery> tests = new ArrayList<SpatialTestQuery>();
+    while( iter.hasNext() ) {
+      tests.add( iter.next() );
+    }
+    Assert.assertEquals( 3, tests.size() );
+
+    SpatialTestQuery sf = tests.get(0);
+   // assert
+    Assert.assertEquals( 1, sf.ids.size() );
+    Assert.assertTrue( sf.ids.get(0).equals( "G5391959" ) );
+    Assert.assertTrue( sf.args.getShape() instanceof Rectangle);
+    Assert.assertEquals( SpatialOperation.IsWithin, sf.args.getOperation() );
+  }
+
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/BaseSpatialContextTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/BaseSpatialContextTestCase.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/BaseSpatialContextTestCase.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/BaseSpatialContextTestCase.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,169 @@
+/*
+ * 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.base.context;
+
+import org.apache.lucene.spatial.base.query.SpatialArgs;
+import org.apache.lucene.spatial.base.query.SpatialArgsParser;
+import org.apache.lucene.spatial.base.query.SpatialOperation;
+import org.apache.lucene.spatial.base.shape.MultiShape;
+import org.apache.lucene.spatial.base.shape.Point;
+import org.apache.lucene.spatial.base.shape.Rectangle;
+import org.apache.lucene.spatial.base.shape.Shape;
+import org.apache.lucene.spatial.base.shape.simple.CircleImpl;
+import org.apache.lucene.spatial.base.shape.simple.PointImpl;
+import org.apache.lucene.spatial.base.shape.simple.RectangleImpl;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+
+/**
+ */
+@SuppressWarnings("unchecked")
+public abstract class BaseSpatialContextTestCase {
+
+  protected abstract SpatialContext getSpatialContext();
+
+  public static void checkArgParser(SpatialContext ctx) {
+    SpatialArgsParser parser = new SpatialArgsParser();
+
+    String arg = SpatialOperation.IsWithin + "(-10 -20 10 20)";
+    SpatialArgs out = parser.parse(arg, ctx);
+    assertEquals(SpatialOperation.IsWithin, out.getOperation());
+    Rectangle bounds = (Rectangle) out.getShape();
+    assertEquals(-10.0, bounds.getMinX(), 0D);
+    assertEquals(10.0, bounds.getMaxX(), 0D);
+
+    // Disjoint should not be scored
+    arg = SpatialOperation.IsDisjointTo + " (-10 10 -20 20)";
+    out = parser.parse(arg, ctx);
+    assertEquals(SpatialOperation.IsDisjointTo, out.getOperation());
+
+    try {
+      parser.parse(SpatialOperation.IsDisjointTo + "[ ]", ctx);
+      fail("spatial operations need args");
+    }
+    catch (Exception ex) {//expected
+    }
+
+    try {
+      parser.parse("XXXX(-10 10 -20 20)", ctx);
+      fail("unknown operation!");
+    }
+    catch (Exception ex) {//expected
+    }
+  }
+
+  public static void checkShapesImplementEquals( Class[] classes ) {
+
+    for( Class clazz : classes ) {
+      try {
+        clazz.getDeclaredMethod( "equals", Object.class );
+      } catch (Exception e) {
+        Assert.fail( "Shape needs to define 'equals' : " + clazz.getName() );
+      }
+      try {
+        clazz.getDeclaredMethod( "hashCode" );
+      } catch (Exception e) {
+        Assert.fail( "Shape needs to define 'hashCode' : " + clazz.getName() );
+      }
+    }
+  }
+
+  public static interface WriteReader {
+    Shape writeThenRead( Shape s ) throws IOException;
+  }
+
+  public static void checkBasicShapeIO( SpatialContext ctx, WriteReader help ) throws Exception {
+
+    // Simple Point
+    Shape s = ctx.readShape("10 20");
+    assertEquals(s,ctx.readShape("20,10"));//check comma for y,x format
+    assertEquals(s,ctx.readShape("20, 10"));//test space
+    Point p = (Point) s;
+    assertEquals(10.0, p.getX(), 0D);
+    assertEquals(20.0, p.getY(), 0D);
+    p = (Point) help.writeThenRead(s);
+    assertEquals(10.0, p.getX(), 0D);
+    assertEquals(20.0, p.getY(), 0D);
+    Assert.assertFalse(s.hasArea());
+
+    // BBOX
+    s = ctx.readShape("-10 -20 10 20");
+    Rectangle b = (Rectangle) s;
+    assertEquals(-10.0, b.getMinX(), 0D);
+    assertEquals(-20.0, b.getMinY(), 0D);
+    assertEquals(10.0, b.getMaxX(), 0D);
+    assertEquals(20.0, b.getMaxY(), 0D);
+    b = (Rectangle) help.writeThenRead(s);
+    assertEquals(-10.0, b.getMinX(), 0D);
+    assertEquals(-20.0, b.getMinY(), 0D);
+    assertEquals(10.0, b.getMaxX(), 0D);
+    assertEquals(20.0, b.getMaxY(), 0D);
+    Assert.assertTrue(s.hasArea());
+
+    // Point/Distance
+    s = ctx.readShape("Circle( 1.23 4.56 distance=7.89)");
+    CircleImpl circle = (CircleImpl)s;
+    assertEquals(1.23, circle.getCenter().getX(), 0D);
+    assertEquals(4.56, circle.getCenter().getY(), 0D);
+    assertEquals(7.89, circle.getDistance(), 0D);
+    Assert.assertTrue(s.hasArea());
+
+    Shape s2 = ctx.readShape("Circle( 4.56,1.23 d=7.89 )"); // use lat,lon and use 'd' abbreviation
+    assertEquals(s,s2);
+  }
+
+  //--------------------------------------------------------------
+  // Actual tests
+  //--------------------------------------------------------------
+
+  @Test
+  public void testArgsParser() throws Exception {
+    checkArgParser( getSpatialContext() );
+  }
+
+  @Test
+  public void testImplementsEqualsAndHash() throws Exception {
+    checkShapesImplementEquals( new Class[] {
+      PointImpl.class,
+      CircleImpl.class,
+      RectangleImpl.class,
+      MultiShape.class,
+    });
+  }
+
+  @Test
+  public void testSimpleShapeIO() throws Exception {
+    final SpatialContext io =  getSpatialContext();
+    checkBasicShapeIO( io, new WriteReader() {
+      @Override
+      public Shape writeThenRead(Shape s) {
+        String buff = io.toString( s );
+        return io.readShape( buff );
+      }
+    });
+  }
+
+  //Looking for more tests?  Shapes are tested in TestShapes2D.
+
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/SpatialContextFactoryTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/SpatialContextFactoryTest.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/SpatialContextFactoryTest.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/SpatialContextFactoryTest.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,94 @@
+package org.apache.lucene.spatial.base.context;/*
+ * 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.
+ */
+
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.distance.DistanceUnits;
+import org.apache.lucene.spatial.base.distance.CartesianDistCalc;
+import org.apache.lucene.spatial.base.distance.GeodesicSphereDistCalc;
+import org.apache.lucene.spatial.base.shape.simple.RectangleImpl;
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static junit.framework.Assert.assertEquals;
+
+/**
+ * @author dsmiley
+ */
+public class SpatialContextFactoryTest {
+  public static final String PROP = "SpatialContextFactory";
+
+  @After
+  public void tearDown() {
+    System.getProperties().remove(PROP);
+  }
+  
+  private SpatialContext call(String... argsStr) {
+    Map<String,String> args = new HashMap<String,String>();
+    for (int i = 0; i < argsStr.length; i+=2) {
+      String key = argsStr[i];
+      String val = argsStr[i+1];
+      args.put(key,val);
+    }
+    return SpatialContextFactory.makeSpatialContext(args, getClass().getClassLoader());
+  }
+  
+  @Test
+  public void testDefault() {
+    SpatialContext s = SimpleSpatialContext.GEO_KM;
+    SpatialContext t = call();//default
+    assertEquals(s.getClass(),t.getClass());
+    assertEquals(s.getUnits(),t.getUnits());
+    assertEquals(s.getDistCalc(),t.getDistCalc());
+    assertEquals(s.getWorldBounds(),t.getWorldBounds());
+  }
+  
+  @Test
+  public void testCustom() {
+    SpatialContext sc = call("units","u");
+    assertEquals(DistanceUnits.CARTESIAN,sc.getUnits());
+    assertEquals(new CartesianDistCalc(),sc.getDistCalc());
+
+    sc = call("units","u",
+        "distCalculator","cartesian^2",
+        "worldBounds","-100 0 75 200");//West South East North
+    assertEquals(new CartesianDistCalc(true),sc.getDistCalc());
+    assertEquals(new RectangleImpl(-100,75,0,200),sc.getWorldBounds());
+
+    sc = call("units","miles",
+        "distCalculator","lawOfCosines");
+    assertEquals(DistanceUnits.MILES,sc.getUnits());
+    assertEquals(new GeodesicSphereDistCalc.LawOfCosines(sc.getUnits().earthRadius()),
+        sc.getDistCalc());
+  }
+  
+  @Test
+  public void testSystemPropertyLookup() {
+    System.setProperty(PROP,DSCF.class.getName());
+    assertEquals(DistanceUnits.CARTESIAN,call().getUnits());//DSCF returns this
+  }
+
+  public static class DSCF extends SpatialContextFactory {
+
+    @Override
+    protected SpatialContext newSpatialContext() {
+      return new SimpleSpatialContext(DistanceUnits.CARTESIAN);
+    }
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/SpatialContextTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/SpatialContextTestCase.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/SpatialContextTestCase.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/context/SpatialContextTestCase.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,31 @@
+/*
+ * 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.base.context;
+
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+
+
+/**
+ */
+public class SpatialContextTestCase extends BaseSpatialContextTestCase {
+
+  @Override
+  protected SpatialContext getSpatialContext() {
+    return SimpleSpatialContext.GEO_KM;
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/distance/TestDistances.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/distance/TestDistances.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/distance/TestDistances.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/distance/TestDistances.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,269 @@
+/*
+ * 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.base.distance;
+
+import org.apache.lucene.spatial.RandomSeed;
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.shape.SpatialRelation;
+import org.apache.lucene.spatial.base.shape.Point;
+import org.apache.lucene.spatial.base.shape.Rectangle;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Random;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author David Smiley - dsmiley@mitre.org
+ */
+public class TestDistances {
+
+  private final Random random = new Random(RandomSeed.seed());
+  //NOTE!  These are sometimes modified by tests.
+  private SpatialContext ctx;
+  private double EPS;
+
+  @Before
+  public void beforeTest() {
+    ctx = new SimpleSpatialContext(DistanceUnits.KILOMETERS);
+    EPS = 10e-4;//delta when doing double assertions. Geo eps is not that small.
+  }
+
+  private DistanceCalculator dc() {
+    return ctx.getDistCalc();
+  }
+  
+  @Test
+  public void testSomeDistances() {
+    //See to verify: from http://www.movable-type.co.uk/scripts/latlong.html
+    Point ctr = pLL(0,100);
+    assertEquals(11100, dc().distance(ctr, pLL(10, 0)),3);
+    assertEquals(11100, dc().distance(ctr, pLL(10, -160)),3);
+
+    assertEquals(314.40338, dc().distance(pLL(1, 2), pLL(3, 4)),EPS);
+  }
+
+  @Test
+  public void testCalcBoxByDistFromPt() {
+    //first test regression
+    {
+      double d = 6894.1;
+      Point pCtr = pLL(-20, 84);
+      Point pTgt = pLL(-42, 15);
+      assertTrue(dc().distance(pCtr, pTgt) < d);
+      //since the pairwise distance is less than d, a bounding box from ctr with d should contain pTgt.
+      Rectangle r = dc().calcBoxByDistFromPt(pCtr, d, ctx);
+      assertEquals(SpatialRelation.CONTAINS,r.relate(pTgt, ctx));
+      checkBBox(pCtr,d);
+    }
+
+    assertEquals("0 dist, horiz line",
+        -45,dc().calcBoxByDistFromPtHorizAxis(ctx.makePoint(-180,-45),0,ctx),0);
+
+    double MAXDIST = ctx.getUnits().earthCircumference() / 2;
+    checkBBox(ctx.makePoint(0,0), MAXDIST);
+    checkBBox(ctx.makePoint(0,0), MAXDIST *0.999999);
+    checkBBox(ctx.makePoint(0,0),0);
+    checkBBox(ctx.makePoint(0,0),0.000001);
+    checkBBox(ctx.makePoint(0,90),0.000001);
+    checkBBox(ctx.makePoint(-32.7,-5.42),9829);
+    checkBBox(ctx.makePoint(0,90-20),ctx.getDistCalc().degreesToDistance(20));
+    {
+      double d = 0.010;//10m
+      checkBBox(ctx.makePoint(0,90-ctx.getDistCalc().distanceToDegrees(d+0.001)),d);
+    }
+
+    for (int T = 0; T < 100; T++) {
+      double lat = -90 + random.nextDouble()*180;
+      double lon = -180 + random.nextDouble()*360;
+      Point ctr = ctx.makePoint(lon, lat);
+      double dist = MAXDIST*random.nextDouble();
+      checkBBox(ctr, dist);
+    }
+
+  }
+
+  private void checkBBox(Point ctr, double dist) {
+    String msg = "ctr: "+ctr+" dist: "+dist;
+
+    Rectangle r = dc().calcBoxByDistFromPt(ctr, dist, ctx);
+    double horizAxisLat = dc().calcBoxByDistFromPtHorizAxis(ctr,dist, ctx);
+    if (!Double.isNaN(horizAxisLat))
+      assertTrue(r.relate_yRange(horizAxisLat, horizAxisLat, ctx).intersects());
+
+    //horizontal
+    if (r.getWidth() >= 180) {
+      double calcDist = dc().distance(ctr,r.getMinX(), r.getMaxY() == 90 ? 90 : -90 );
+      assertTrue(msg,calcDist <= dist+EPS);
+      //horizAxisLat is meaningless in this context
+    } else {
+      Point tPt = findClosestPointOnVertToPoint(r.getMinX(), r.getMinY(), r.getMaxY(), ctr);
+      double calcDist = dc().distance(ctr,tPt);
+      assertEquals(msg,dist,calcDist,EPS);
+      assertEquals(msg,tPt.getY(),horizAxisLat,EPS);
+    }
+    
+    //vertical
+    double topDist = dc().distance(ctr,ctr.getX(),r.getMaxY());
+    if (r.getMaxY() == 90)
+      assertTrue(msg,topDist <= dist+EPS);
+    else
+      assertEquals(msg,dist,topDist,EPS);
+    double botDist = dc().distance(ctr,ctr.getX(),r.getMinY());
+    if (r.getMinY() == -90)
+      assertTrue(msg,botDist <= dist+EPS);
+    else
+      assertEquals(msg,dist,botDist,EPS);
+  }
+
+  private Point findClosestPointOnVertToPoint(double lon, double lowLat, double highLat, Point ctr) {
+    //A binary search algorithm to find the point along the vertical lon between lowLat & highLat that is closest
+    // to ctr, and returns the distance.
+    double midLat = (highLat - lowLat)/2 + lowLat;
+    double midLatDist = ctx.getDistCalc().distance(ctr,lon,midLat);
+    for(int L = 0; L < 100 && (highLat - lowLat > 0.001|| L < 20); L++) {
+      boolean bottom = (midLat - lowLat > highLat - midLat);
+      double newMid = bottom ? (midLat - lowLat)/2 + lowLat : (highLat - midLat)/2 + midLat;
+      double newMidDist = ctx.getDistCalc().distance(ctr,lon,newMid);
+      if (newMidDist < midLatDist) {
+        if (bottom) {
+          highLat = midLat;
+        } else {
+          lowLat = midLat;
+        }
+        midLat = newMid;
+        midLatDist = newMidDist;
+      } else {
+        if (bottom) {
+          lowLat = newMid;
+        } else {
+          highLat = newMid;
+        }
+      }
+    }
+    return ctx.makePoint(lon,midLat);
+  }
+
+  @Test
+  public void testDistCalcPointOnBearing_cartesian() {
+    ctx = new SimpleSpatialContext(DistanceUnits.CARTESIAN);
+    EPS = 10e-6;//tighter epsilon (aka delta)
+    for(int i = 0; i < 1000; i++) {
+      testDistCalcPointOnBearing(random.nextInt(100));
+    }
+  }
+
+  @Test
+  public void testDistCalcPointOnBearing_geo() {
+    //The haversine formula has a higher error if the points are near antipodal. We adjust EPS tolerance for this case.
+    //TODO Eventually we should add the Vincenty formula for improved accuracy, or try some other cleverness.
+
+    //test known high delta
+//    {
+//      Point c = ctx.makePoint(-103,-79);
+//      double angRAD = Math.toRadians(236);
+//      double dist = 20025;
+//      Point p2 = dc().pointOnBearingRAD(c, dist, angRAD, ctx);
+//      //Pt(x=76.61200011750923,y=79.04946929870962)
+//      double calcDist = dc().distance(c, p2);
+//      assertEqualsRatio(dist, calcDist);
+//    }
+    double maxDist = ctx.getUnits().earthCircumference() / 2;
+    for(int i = 0; i < 1000; i++) {
+      int dist = random.nextInt((int) maxDist);
+      EPS = (dist < maxDist*0.75 ? 10e-6 : 10e-3);
+      testDistCalcPointOnBearing(dist);
+    }
+  }
+
+  private void testDistCalcPointOnBearing(double dist) {
+    for(int angDEG = 0; angDEG < 360; angDEG += random.nextInt(20)+1) {
+      Point c = ctx.makePoint(random.nextInt(360),-90+random.nextInt(181));
+
+      //0 distance means same point
+      Point p2 = dc().pointOnBearing(c, 0, angDEG, ctx);
+      assertEquals(c,p2);
+
+      p2 = dc().pointOnBearing(c, dist, angDEG, ctx);
+      double calcDist = dc().distance(c, p2);
+      assertEqualsRatio(dist, calcDist);
+    }
+  }
+
+  private void assertEqualsRatio(double expected, double actual) {
+    double delta = Math.abs(actual - expected);
+    double base = Math.min(actual, expected);
+    double deltaRatio = base==0 ? delta : Math.min(delta,delta / base);
+    assertEquals(0,deltaRatio, EPS);
+  }
+
+  @Test
+  public void testNormLat() {
+    double[][] lats = new double[][] {
+        {1.23,1.23},//1.23 might become 1.2299999 after some math and we want to ensure that doesn't happen
+        {-90,-90},{90,90},{0,0}, {-100,-80},
+        {-90-180,90},{-90-360,-90},{90+180,-90},{90+360,90},
+        {-12+180,12}};
+    for (double[] pair : lats) {
+      assertEquals("input "+pair[0],pair[1],ctx.normY(pair[0]),0);
+    }
+    Random random = new Random(RandomSeed.seed());
+    for(int i = -1000; i < 1000; i += random.nextInt(10)*10) {
+      double d = ctx.normY(i);
+      assertTrue(i + " " + d, d >= -90 && d <= 90);
+    }
+  }
+
+  @Test
+  public void testNormLon() {
+    double[][] lons = new double[][] {
+        {1.23,1.23},//1.23 might become 1.2299999 after some math and we want to ensure that doesn't happen
+        {-180,-180},{180,-180},{0,0}, {-190,170},
+        {-180-360,-180},{-180-720,-180},{180+360,-180},{180+720,-180}};
+    for (double[] pair : lons) {
+      assertEquals("input "+pair[0],pair[1],ctx.normX(pair[0]),0);
+    }
+    Random random = new Random(RandomSeed.seed());
+    for(int i = -1000; i < 1000; i += random.nextInt(10)*10) {
+      double d = ctx.normX(i);
+      assertTrue(i + " " + d, d >= -180 && d < 180);
+    }
+  }
+
+  @Test
+  public void testDistToRadians() {
+    assertDistToRadians(0);
+    assertDistToRadians(500);
+    assertDistToRadians(ctx.getUnits().earthRadius());
+  }
+
+  private void assertDistToRadians(double dist) {
+    double radius = ctx.getUnits().earthRadius();
+    assertEquals(
+        DistanceUtils.pointOnBearingRAD(0, 0, DistanceUtils.dist2Radians(dist, radius), DistanceUtils.DEG_90_AS_RADS, null)[1],
+        DistanceUtils.dist2Radians(dist, radius),10e-5);
+  }
+
+  private Point pLL(double lat, double lon) {
+    return ctx.makePoint(lon,lat);
+  }
+
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/SpatialPrefixTreeTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/SpatialPrefixTreeTest.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/SpatialPrefixTreeTest.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/SpatialPrefixTreeTest.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.lucene.spatial.base.prefix;
+
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.prefix.geohash.GeohashPrefixTree;
+import org.apache.lucene.spatial.base.shape.Rectangle;
+import org.apache.lucene.spatial.base.shape.Shape;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author David Smiley - dsmiley@mitre.org
+ */
+public class SpatialPrefixTreeTest {
+
+  //TODO plug in others and test them
+  private SimpleSpatialContext ctx;
+  private SpatialPrefixTree trie;
+
+  @Before
+  public void setUp() throws Exception {
+    ctx = SimpleSpatialContext.GEO_KM;
+    trie = new GeohashPrefixTree(ctx,4);
+  }
+
+  @Test
+  public void testNodeTraverse() {
+    Node prevN = null;
+    Node n = trie.getWorldNode();
+    assertEquals(0,n.getLevel());
+    assertEquals(ctx.getWorldBounds(),n.getShape());
+    while(n.getLevel() < trie.getMaxLevels()) {
+      prevN = n;
+      n = n.getSubCells().iterator().next();//TODO random which one?
+      
+      assertEquals(prevN.getLevel()+1,n.getLevel());
+      Rectangle prevNShape = (Rectangle) prevN.getShape();
+      Shape s = n.getShape();
+      Rectangle sbox = s.getBoundingBox();
+      assertTrue(prevNShape.getWidth() > sbox.getWidth());
+      assertTrue(prevNShape.getHeight() > sbox.getHeight());
+    }
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/TestGridMatchInfo.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/TestGridMatchInfo.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/TestGridMatchInfo.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/TestGridMatchInfo.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,68 @@
+/*
+ * 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.base.prefix;
+
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.distance.DistanceUnits;
+import org.apache.lucene.spatial.base.prefix.quad.QuadPrefixTree;
+import org.apache.lucene.spatial.base.shape.Shape;
+import org.apache.lucene.spatial.base.shape.simple.PointImpl;
+import org.apache.lucene.spatial.base.shape.simple.RectangleImpl;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.List;
+
+
+/**
+ */
+public class TestGridMatchInfo {
+
+  @Test @Ignore
+  public void testMatchInfo() {
+    // Check Validation
+    SpatialContext ctx = new SimpleSpatialContext(DistanceUnits.CARTESIAN,null,new RectangleImpl(0,10,0,10));
+    QuadPrefixTree grid = new QuadPrefixTree(ctx, 2);
+
+
+//    GeometricShapeFactory gsf = new GeometricShapeFactory();
+//    gsf.setCentre( new com.vividsolutions.jts.geom.Coordinate( 5,5 ) );
+//    gsf.setSize( 9.5 );
+//    Shape shape = new JtsGeometry( gsf.createCircle() );
+
+    Shape shape = new RectangleImpl(0, 6, 5, 10);
+
+    shape = new PointImpl(3, 3);
+
+    //TODO UPDATE BASED ON NEW API
+    List<String> m = SpatialPrefixTree.nodesToTokenStrings(grid.getNodes(shape,3,false));
+    System.out.println(m);
+
+    for (CharSequence s : m) {
+      System.out.println(s);
+    }
+
+
+//    // query should intersect everything one level down
+//    ArrayList<String> descr = new ArrayList<String>();
+//    descr.add( "AAA*" );
+//    descr.add( "AABC*" );
+//    System.out.println( descr );
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/geohash/TestGeohashUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/geohash/TestGeohashUtils.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/geohash/TestGeohashUtils.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/prefix/geohash/TestGeohashUtils.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,103 @@
+/*
+ * 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.base.prefix.geohash;
+
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.distance.DistanceUnits;
+import org.apache.lucene.spatial.base.shape.Point;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for {@link GeohashUtils}
+ */
+public class TestGeohashUtils {
+  SpatialContext ctx = new SimpleSpatialContext( DistanceUnits.KILOMETERS );
+
+  /**
+   * Pass condition: lat=42.6, lng=-5.6 should be encoded as "ezs42e44yx96",
+   * lat=57.64911 lng=10.40744 should be encoded as "u4pruydqqvj8"
+   */
+  @Test
+  public void testEncode() {
+    String hash = GeohashUtils.encodeLatLon(42.6, -5.6);
+    assertEquals("ezs42e44yx96", hash);
+
+    hash = GeohashUtils.encodeLatLon(57.64911, 10.40744);
+    assertEquals("u4pruydqqvj8", hash);
+  }
+
+  /**
+   * Pass condition: lat=52.3738007, lng=4.8909347 should be encoded and then
+   * decoded within 0.00001 of the original value
+   */
+  @Test
+  public void testDecodePreciseLongitudeLatitude() {
+    String hash = GeohashUtils.encodeLatLon(52.3738007, 4.8909347);
+
+    Point point = GeohashUtils.decode(hash,ctx);
+
+    assertEquals(52.3738007, point.getY(), 0.00001D);
+    assertEquals(4.8909347, point.getX(), 0.00001D);
+  }
+
+  /**
+   * Pass condition: lat=84.6, lng=10.5 should be encoded and then decoded
+   * within 0.00001 of the original value
+   */
+  @Test
+  public void testDecodeImpreciseLongitudeLatitude() {
+    String hash = GeohashUtils.encodeLatLon(84.6, 10.5);
+
+    Point point = GeohashUtils.decode(hash, ctx);
+
+    assertEquals(84.6, point.getY(), 0.00001D);
+    assertEquals(10.5, point.getX(), 0.00001D);
+  }
+
+  /*
+   * see https://issues.apache.org/jira/browse/LUCENE-1815 for details
+   */
+  @Test
+  public void testDecodeEncode() {
+    String geoHash = "u173zq37x014";
+    assertEquals(geoHash, GeohashUtils.encodeLatLon(52.3738007, 4.8909347));
+    Point point = GeohashUtils.decode(geoHash,ctx);
+    assertEquals(52.37380061d, point.getY(), 0.000001d);
+    assertEquals(4.8909343d, point.getX(), 0.000001d);
+
+    assertEquals(geoHash, GeohashUtils.encodeLatLon(point.getY(), point.getX()));
+
+    geoHash = "u173";
+    point = GeohashUtils.decode("u173",ctx);
+    geoHash = GeohashUtils.encodeLatLon(point.getY(), point.getX());
+    final Point point2 = GeohashUtils.decode(geoHash, ctx);
+    assertEquals(point.getY(), point2.getY(), 0.000001d);
+    assertEquals(point.getX(), point2.getX(), 0.000001d);
+  }
+
+  /** see the table at http://en.wikipedia.org/wiki/Geohash */
+  @Test
+  public void testHashLenToWidth() {
+    double[] box = GeohashUtils.lookupDegreesSizeForHashLen(3);
+    assertEquals(1.40625,box[0],0.0001);
+    assertEquals(1.40625,box[1],0.0001);
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/AbstractTestShapes.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/AbstractTestShapes.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/AbstractTestShapes.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/AbstractTestShapes.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,261 @@
+/*
+ * 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.base.shape;
+
+import org.apache.lucene.spatial.RandomSeed;
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.distance.DistanceCalculator;
+import org.junit.Before;
+
+import java.util.Random;
+
+import static org.apache.lucene.spatial.base.shape.SpatialRelation.CONTAINS;
+import static org.apache.lucene.spatial.base.shape.SpatialRelation.DISJOINT;
+import static org.apache.lucene.spatial.base.shape.SpatialRelation.WITHIN;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author David Smiley - dsmiley@mitre.org
+ */
+public abstract class AbstractTestShapes {
+  protected Random random;
+
+  protected SpatialContext ctx;
+  private static final double EPS = 10e-9;
+
+  @Before
+  public void beforeClass() {
+    random = new Random(RandomSeed.seed());
+    ctx = getContext();
+  }
+
+  protected void assertRelation(String msg, SpatialRelation expected, Shape a, Shape b) {
+    msg = a+" intersect "+b;//use different msg
+    _assertIntersect(msg,expected,a,b);
+    //check flipped a & b w/ transpose(), while we're at it
+    _assertIntersect("(transposed) " + msg, expected.transpose(), b, a);
+  }
+
+  private void _assertIntersect(String msg, SpatialRelation expected, Shape a, Shape b) {
+    SpatialRelation sect = a.relate(b, ctx);
+    if (sect == expected)
+      return;
+    if (expected == WITHIN || expected == CONTAINS) {
+      if (a.getClass().equals(b.getClass())) // they are the same shape type
+        assertEquals(msg,a,b);
+      else {
+        //they are effectively points or lines that are the same location
+        assertTrue(msg,!a.hasArea());
+        assertTrue(msg,!b.hasArea());
+
+        Rectangle aBBox = a.getBoundingBox();
+        Rectangle bBBox = b.getBoundingBox();
+        if (aBBox.getHeight() == 0 && bBBox.getHeight() == 0
+            && (aBBox.getMaxY() == 90 && bBBox.getMaxY() == 90
+          || aBBox.getMinY() == -90 && bBBox.getMinY() == -90))
+          ;//== a point at the pole
+        else
+          assertEquals(msg, aBBox, bBBox);
+      }
+    } else {
+      assertEquals(msg,expected,sect);
+    }
+  }
+
+  private void assertEqualsRatio(String msg, double expected, double actual) {
+    double delta = Math.abs(actual - expected);
+    double base = Math.min(actual, expected);
+    double deltaRatio = base==0 ? delta : Math.min(delta,delta / base);
+    assertEquals(msg,0,deltaRatio, EPS);
+  }
+
+  protected void testRectangle(double minX, double width, double minY, double height) {
+    Rectangle r = ctx.makeRect(minX, minX + width, minY, minY+height);
+    //test equals & hashcode of duplicate
+    Rectangle r2 = ctx.makeRect(minX, minX + width, minY, minY+height);
+    assertEquals(r,r2);
+    assertEquals(r.hashCode(),r2.hashCode());
+
+    String msg = r.toString();
+
+    assertEquals(msg, width != 0 && height != 0, r.hasArea());
+    assertEquals(msg, width != 0 && height != 0, r.getArea() > 0);
+
+    assertEqualsRatio(msg, height, r.getHeight());
+    assertEqualsRatio(msg, width, r.getWidth());
+    Point center = r.getCenter();
+    msg += " ctr:"+center;
+    //System.out.println(msg);
+    assertRelation(msg, CONTAINS, r, center);
+
+    DistanceCalculator dc = ctx.getDistCalc();
+    double dUR = dc.distance(center, r.getMaxX(), r.getMaxY());
+    double dLR = dc.distance(center, r.getMaxX(), r.getMinY());
+    double dUL = dc.distance(center, r.getMinX(), r.getMaxY());
+    double dLL = dc.distance(center, r.getMinX(), r.getMinY());
+
+    assertEquals(msg,width != 0 || height != 0, dUR != 0);
+    if (dUR != 0)
+      assertTrue(dUR > 0 && dLL > 0);
+    assertEqualsRatio(msg, dUR, dUL);
+    assertEqualsRatio(msg, dLR, dLL);
+    if (!ctx.isGeo() || center.getY() == 0)
+      assertEqualsRatio(msg, dUR, dLL);
+  }
+
+  protected void testRectIntersect() {
+    final double INCR = 45;
+    final double Y = 10;
+    for(double left = -180; left <= 180; left += INCR) {
+      for(double right = left; right - left <= 360; right += INCR) {
+        Rectangle r = ctx.makeRect(left,right,-Y,Y);
+
+        //test contains (which also tests within)
+        for(double left2 = left; left2 <= right; left2 += INCR) {
+          for(double right2 = left2; right2 <= right; right2 += INCR) {
+            Rectangle r2 = ctx.makeRect(left2,right2,-Y,Y);
+            assertRelation(null, SpatialRelation.CONTAINS, r, r2);
+          }
+        }
+        //test point contains
+        assertRelation(null, SpatialRelation.CONTAINS, r, ctx.makePoint(left, Y));
+
+        //test disjoint
+        for(double left2 = right+INCR; left2 - left < 360; left2 += INCR) {
+          for(double right2 = left2; right2 - left < 360; right2 += INCR) {
+            Rectangle r2 = ctx.makeRect(left2,right2,-Y,Y);
+            assertRelation(null, SpatialRelation.DISJOINT, r, r2);
+
+            //test point disjoint
+            assertRelation(null, SpatialRelation.DISJOINT, r, ctx.makePoint(left2, Y));
+          }
+        }
+        //test intersect
+        for(double left2 = left+INCR; left2 <= right; left2 += INCR) {
+          for(double right2 = right+INCR; right2 - left < 360; right2 += INCR) {
+            Rectangle r2 = ctx.makeRect(left2,right2,-Y,Y);
+            assertRelation(null, SpatialRelation.INTERSECTS, r, r2);
+          }
+        }
+
+      }
+    }
+  }
+
+  protected void testCircle(double x, double y, double dist) {
+    Circle c = ctx.makeCircle(x, y, dist);
+    String msg = c.toString();
+    final Circle c2 = ctx.makeCircle(ctx.makePoint(x, y), dist);
+    assertEquals(c, c2);
+    assertEquals(c.hashCode(),c2.hashCode());
+
+    assertEquals(msg,dist > 0, c.hasArea());
+    final Rectangle bbox = c.getBoundingBox();
+    assertEquals(msg,dist > 0, bbox.getArea() > 0);
+    if (!ctx.isGeo()) {
+      //if not geo then units of dist == units of x,y
+      assertEqualsRatio(msg, bbox.getHeight(), dist * 2);
+      assertEqualsRatio(msg, bbox.getWidth(), dist * 2);
+    }
+    assertRelation(msg, CONTAINS, c, c.getCenter());
+    assertRelation(msg, CONTAINS, bbox, c);
+  }
+
+  protected void testCircleIntersect() {
+    //Now do some randomized tests:
+    int i_C = 0, i_I = 0, i_W = 0, i_O = 0;//counters for the different intersection cases
+    int laps = 0;
+    int MINLAPSPERCASE = 20;
+    while(i_C < MINLAPSPERCASE || i_I < MINLAPSPERCASE || i_W < MINLAPSPERCASE || i_O < MINLAPSPERCASE) {
+      laps++;
+      double cX = randRange(-180,179);
+      double cY = randRange(-90,90);
+      double cR = randRange(0, 180);
+      double cR_dist = ctx.getDistCalc().distance(ctx.makePoint(0, 0), 0, cR);
+      Circle c = ctx.makeCircle(cX, cY, cR_dist);
+
+      double rX = randRange(-180,179);
+      double rW = randRange(0,360);
+      double rY1 = randRange(-90,90);
+      double rY2 = randRange(-90,90);
+      double rYmin = Math.min(rY1,rY2);
+      double rYmax = Math.max(rY1,rY2);
+      Rectangle r = ctx.makeRect(rX, rX+rW, rYmin, rYmax);
+
+      SpatialRelation ic = c.relate(r, ctx);
+
+      Point p;
+      switch (ic) {
+        case CONTAINS:
+          i_C++;
+          p = randomPointWithin(random,r,ctx);
+          assertEquals(CONTAINS,c.relate(p, ctx));
+          break;
+        case INTERSECTS:
+          i_I++;
+          //hard to test anything here; instead we'll test it separately
+          break;
+        case WITHIN:
+          i_W++;
+          p = randomPointWithin(random,c,ctx);
+          assertEquals(CONTAINS,r.relate(p, ctx));
+          break;
+        case DISJOINT:
+          i_O++;
+          p = randomPointWithin(random,r,ctx);
+          assertEquals(DISJOINT,c.relate(p, ctx));
+          break;
+        default: fail(""+ic);
+      }
+    }
+    System.out.println("Laps: "+laps);
+
+    //TODO deliberately test INTERSECTS based on known intersection point
+  }
+
+  /** Returns a random integer between [start, end] with a limited number of possibilities instead of end-start+1. */
+  private int randRange(int start, int end) {
+    //I tested this.
+    double r = random.nextDouble();
+    final int BUCKETS = 91;
+    int ir = (int) Math.round(r*(BUCKETS-1));//put into buckets
+    int result = (int)((double)((end - start) * ir) / (double)(BUCKETS-1) + (double)start);
+    assert result >= start && result <= end;
+    return result;
+  }
+
+  private Point randomPointWithin(Random random, Circle c, SpatialContext ctx) {
+    double d = c.getDistance() * random.nextDouble();
+    double angleDEG = 360*random.nextDouble();
+    Point p = ctx.getDistCalc().pointOnBearing(c.getCenter(), d, angleDEG, ctx);
+    assertEquals(CONTAINS,c.relate(p, ctx));
+    return p;
+  }
+
+  private Point randomPointWithin(Random random, Rectangle r, SpatialContext ctx) {
+    double x = r.getMinX() + random.nextDouble()*r.getWidth();
+    double y = r.getMinY() + random.nextDouble()*r.getHeight();
+    Point p = ctx.makePoint(x,y);
+    assertEquals(CONTAINS,r.relate(p, ctx));
+    return p;
+  }
+
+  protected abstract SpatialContext getContext();
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/TestShapes2D.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/TestShapes2D.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/TestShapes2D.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/TestShapes2D.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,94 @@
+/*
+ * 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.base.shape;
+
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.distance.DistanceUnits;
+import org.junit.Test;
+
+import static org.apache.lucene.spatial.base.shape.SpatialRelation.*;
+import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author dsmiley
+ */
+public class TestShapes2D extends AbstractTestShapes {
+
+  @Override
+  protected SpatialContext getContext() {
+    return new SimpleSpatialContext(DistanceUnits.CARTESIAN);
+  }
+
+  @Test
+  public void testSimplePoint() {
+    Point pt = ctx.makePoint(0,0);
+    String msg = pt.toString();
+
+    //test equals & hashcode
+    Point pt2 = ctx.makePoint(0,0);
+    assertEquals(msg, pt, pt2);
+    assertEquals(msg, pt.hashCode(), pt2.hashCode());
+
+    assertFalse(msg,pt.hasArea());
+    assertEquals(msg,pt.getCenter(),pt);
+    Rectangle bbox = pt.getBoundingBox();
+    assertFalse(msg,bbox.hasArea());
+    assertEquals(msg,pt,bbox.getCenter());
+
+    assertRelation(msg, CONTAINS, pt, pt2);
+    assertRelation(msg, DISJOINT, pt, ctx.makePoint(0, 1));
+    assertRelation(msg, DISJOINT, pt, ctx.makePoint(1, 0));
+    assertRelation(msg, DISJOINT, pt, ctx.makePoint(1, 1));
+  }
+
+  @Test
+  public void testSimpleRectangle() {
+    double[] minXs = new double[]{-1000,-360,-180,-20,0,20,180,1000};
+    for (double minX : minXs) {
+      double[] widths = new double[]{0,10,180,360,400};
+      for (double width : widths) {
+        testRectangle(minX, width, 0, 0);
+        testRectangle(minX, width, -10, 10);
+        testRectangle(minX, width, 5, 10);
+      }
+    }
+
+    testRectIntersect();
+  }
+
+  @Test
+  public void testSimpleCircle() {
+    double[] theXs = new double[]{-10,0,10};
+    for (double x : theXs) {
+      double[] theYs = new double[]{-20,0,20};
+      for (double y : theYs) {
+        testCircle(x, y, 0);
+        testCircle(x, y, 5);
+      }
+    }
+    //INTERSECTION:
+    //Start with some static tests that have shown to cause failures at some point:
+    assertEquals("getX not getY",INTERSECTS,ctx.makeCircle(107,-81,147).relate(ctx.makeRect(92, 121, -89, 74), ctx));
+
+    testCircleIntersect();
+  }
+
+
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/TestShapesGeo.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/TestShapesGeo.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/TestShapesGeo.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/base/shape/TestShapesGeo.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,165 @@
+/*
+ * 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.base.shape;
+
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.distance.*;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.lucene.spatial.base.shape.SpatialRelation.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author David Smiley - dsmiley@mitre.org
+ */
+public abstract class TestShapesGeo extends AbstractTestShapes {
+
+  @Test
+  public void testGeoRectangle() {
+    double[] lons = new double[]{0,45,160,180,-45,-175, -180};//minX
+    for (double lon : lons) {
+      double[] lonWs = new double[]{0,20,180,200,355, 360};//width
+      for (double lonW : lonWs) {
+        testRectangle(lon, lonW, 0, 0);
+        testRectangle(lon, lonW, -10, 10);
+        testRectangle(lon, lonW, 80, 10);//polar cap
+        testRectangle(lon, lonW, -90, 180);//full lat range
+      }
+    }
+
+    //Test geo rectangle intersections
+    testRectIntersect();
+  }
+
+
+  @Test
+  public void testGeoCircle() {
+    //--Start with some static tests that once failed:
+
+    //Bug: numeric edge at pole, fails to init
+    ctx.makeCircle(
+        110,-12,ctx.getDistCalc().degreesToDistance(90 + 12));
+
+    //Bug: horizXAxis not in enclosing rectangle, assertion
+    ctx.makeCircle(-44,16,degToDist(106));
+    ctx.makeCircle(-36,-76,degToDist(14));
+    ctx.makeCircle(107,82,degToDist(172));
+
+// TODO need to update this test to be valid
+//    {
+//      //Bug in which distance was being confused as being in the same coordinate system as x,y.
+//      double distDeltaToPole = 0.001;//1m
+//      double distDeltaToPoleDEG = ctx.getDistCalc().distanceToDegrees(distDeltaToPole);
+//      double dist = 1;//1km
+//      double distDEG = ctx.getDistCalc().distanceToDegrees(dist);
+//      Circle c = ctx.makeCircle(0,90-distDeltaToPoleDEG-distDEG,dist);
+//      Rectangle cBBox = c.getBoundingBox();
+//      Rectangle r = ctx.makeRect(cBBox.getMaxX()*0.99,cBBox.getMaxX()+1,c.getCenter().getY(),c.getCenter().getY());
+//      assertEquals(INTERSECTS,c.getBoundingBox().relate(r, ctx));
+//      assertEquals("dist != xy space",INTERSECTS,c.relate(r,ctx));//once failed here
+//    }
+
+    assertEquals("wrong estimate", DISJOINT,ctx.makeCircle(-166,59,5226.2).relate(ctx.makeRect(36, 66, 23, 23), ctx));
+
+    assertEquals("bad CONTAINS (dateline)",INTERSECTS,ctx.makeCircle(56,-50,12231.5).relate(ctx.makeRect(108, 26, 39, 48), ctx));
+
+    assertEquals("bad CONTAINS (backwrap2)",INTERSECTS,
+        ctx.makeCircle(112,-3,degToDist(91)).relate(ctx.makeRect(-163, 29, -38, 10), ctx));
+
+    assertEquals("bad CONTAINS (r x-wrap)",INTERSECTS,
+        ctx.makeCircle(-139,47,degToDist(80)).relate(ctx.makeRect(-180, 180, -3, 12), ctx));
+
+    assertEquals("bad CONTAINS (pwrap)",INTERSECTS,
+        ctx.makeCircle(-139,47,degToDist(80)).relate(ctx.makeRect(-180, 179, -3, 12), ctx));
+
+    assertEquals("no-dist 1",WITHIN,
+        ctx.makeCircle(135,21,0).relate(ctx.makeRect(-103, -154, -47, 52), ctx));
+
+    assertEquals("bbox <= >= -90 bug",CONTAINS,
+        ctx.makeCircle(-64,-84,degToDist(124)).relate(ctx.makeRect(-96, 96, -10, -10), ctx));
+
+    //The horizontal axis line of a geo circle doesn't necessarily pass through c's ctr.
+    assertEquals("c's horiz axis doesn't pass through ctr",INTERSECTS,
+        ctx.makeCircle(71,-44,degToDist(40)).relate(ctx.makeRect(15, 27, -62, -34), ctx));
+
+    assertEquals("pole boundary",INTERSECTS,
+        ctx.makeCircle(-100,-12,degToDist(102)).relate(ctx.makeRect(143, 175, 4, 32), ctx));
+
+    assertEquals("full circle assert",CONTAINS,
+        ctx.makeCircle(-64,32,degToDist(180)).relate(ctx.makeRect(47, 47, -14, 90), ctx));
+
+    //--Now proceed with systematic testing:
+
+    double distToOpposeSide = ctx.getUnits().earthRadius()*Math.PI;
+    assertEquals(ctx.getWorldBounds(),ctx.makeCircle(0,0,distToOpposeSide).getBoundingBox());
+    //assertEquals(ctx.makeCircle(0,0,distToOpposeSide/2 - 500).getBoundingBox());
+
+    double[] theXs = new double[]{-180,-45,90};
+    for (double x : theXs) {
+      double[] theYs = new double[]{-90,-45,0,45,90};
+      for (double y : theYs) {
+        testCircle(x, y, 0);
+        testCircle(x, y, 500);
+        testCircle(x, y, degToDist(90));
+        testCircle(x, y, ctx.getUnits().earthRadius()*6);
+      }
+    }
+
+    testCircleIntersect();
+  }
+
+  private double degToDist(int deg) {
+    return ctx.getDistCalc().degreesToDistance(deg);
+  }
+
+  @Ignore
+  public static class TestLawOfCosines extends TestShapesGeo {
+
+    @Override
+    protected SpatialContext getContext() {
+      DistanceUnits units = DistanceUnits.KILOMETERS;
+      return new SimpleSpatialContext(units,
+          new GeodesicSphereDistCalc.LawOfCosines(units.earthRadius()),
+          SpatialContext.GEO_WORLDBOUNDS);
+    }
+  }
+
+  public static class TestHaversine extends TestShapesGeo {
+
+    @Override
+    protected SpatialContext getContext() {
+      DistanceUnits units = DistanceUnits.KILOMETERS;
+      return new SimpleSpatialContext(units,
+          new GeodesicSphereDistCalc.Haversine(units.earthRadius()),
+          SpatialContext.GEO_WORLDBOUNDS);
+    }
+  }
+
+  public static class TestVincentySphere extends TestShapesGeo {
+
+    @Override
+    protected SpatialContext getContext() {
+      DistanceUnits units = DistanceUnits.KILOMETERS;
+      return new SimpleSpatialContext(units,
+          new GeodesicSphereDistCalc.Vincenty(units.earthRadius()),
+          SpatialContext.GEO_WORLDBOUNDS);
+    }
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/BaseRecursivePrefixTreeStrategyTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/BaseRecursivePrefixTreeStrategyTestCase.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/BaseRecursivePrefixTreeStrategyTestCase.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/BaseRecursivePrefixTreeStrategyTestCase.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,57 @@
+/*
+ * 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.strategy.prefix;
+
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.prefix.geohash.GeohashPrefixTree;
+import org.apache.lucene.spatial.strategy.SimpleSpatialFieldInfo;
+import org.apache.lucene.spatial.SpatialMatchConcern;
+import org.apache.lucene.spatial.StrategyTestCase;
+import org.junit.Test;
+
+import java.io.IOException;
+
+
+public abstract class BaseRecursivePrefixTreeStrategyTestCase extends StrategyTestCase<SimpleSpatialFieldInfo> {
+
+  private int maxLength;
+
+  protected abstract SpatialContext getSpatialContext();
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    maxLength = GeohashPrefixTree.getMaxLevelsPossible();
+    // SimpleIO
+    this.ctx = getSpatialContext();
+    this.strategy = new RecursivePrefixTreeStrategy(new GeohashPrefixTree(
+        ctx, maxLength ));
+    this.fieldInfo = new SimpleSpatialFieldInfo( getClass().getSimpleName() );
+  }
+
+  @Test
+  public void testFilterWithVariableScanLevel() throws IOException {
+    getAddAndVerifyIndexedDocuments(DATA_WORLD_CITIES_POINTS);
+
+    //execute queries for each prefix grid scan level
+    for(int i = 0; i <= maxLength; i++) {
+      ((RecursivePrefixTreeStrategy)strategy).setPrefixGridScanLevel(i);
+      executeQueries(SpatialMatchConcern.FILTER, QTEST_Cities_IsWithin_BBox);
+    }
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/RecursivePrefixTreeStrategyTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/RecursivePrefixTreeStrategyTestCase.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/RecursivePrefixTreeStrategyTestCase.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/RecursivePrefixTreeStrategyTestCase.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,36 @@
+/*
+ * 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.strategy.prefix;
+
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.junit.Before;
+
+
+public class RecursivePrefixTreeStrategyTestCase extends BaseRecursivePrefixTreeStrategyTestCase {
+
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+  }
+
+  @Override
+  protected SpatialContext getSpatialContext() {
+    return SimpleSpatialContext.GEO_KM;
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/TestSpatialPrefixField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/TestSpatialPrefixField.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/TestSpatialPrefixField.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/TestSpatialPrefixField.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,68 @@
+/*
+ * 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.strategy.prefix;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+
+/**
+ * This is just a quick idea for *simple* tests
+ */
+public class TestSpatialPrefixField {
+
+  @Test
+  public void testRawTokens() {
+    // Ignoring geometry for now, and focus on what tokens need to match
+
+    List<String> docA = Arrays.asList(
+        "AAAAAA*",
+        "AAAAAB+"
+    );
+
+    List<String> docB = Arrays.asList(
+        "A*",
+        "BB*"
+    );
+
+    // Assumptions:
+    checkQuery("AAAAA", "docA", "docB");
+    checkQuery("AAAAA*", "docA", "docB"); // for now * and + are essentially identical
+    checkQuery("AAAAA+", "docA", "docB"); // down the road, there may be a difference between 'covers' and an edge
+
+    checkQuery("AA*", "docB", "docA"); // Bigger input query
+
+    checkQuery("AAAAAAAAAAAA*", "docA", "docB"); // small
+
+    checkQuery("BC"); // nothing
+    checkQuery("XX"); // nothing
+
+    // match only B
+    checkQuery("B", "docB");
+    checkQuery("BBBB", "docB");
+    checkQuery("B*", "docB");
+    checkQuery("BBBB*", "docB");
+  }
+
+  void checkQuery(String query, String... expect) {
+    // TODO, check that the query returns the docs in order
+  }
+
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/TestTermQueryPrefixGridStrategy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/TestTermQueryPrefixGridStrategy.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/TestTermQueryPrefixGridStrategy.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/prefix/TestTermQueryPrefixGridStrategy.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,64 @@
+/*
+ * 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.strategy.prefix;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+import org.apache.lucene.spatial.base.prefix.quad.QuadPrefixTree;
+import org.apache.lucene.spatial.base.query.SpatialArgsParser;
+import org.apache.lucene.spatial.base.shape.Shape;
+import org.apache.lucene.spatial.base.shape.simple.PointImpl;
+import org.apache.lucene.spatial.strategy.SimpleSpatialFieldInfo;
+import org.apache.lucene.spatial.SpatialTestCase;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+
+public class TestTermQueryPrefixGridStrategy extends SpatialTestCase {
+
+  @Test
+  public void testNGramPrefixGridLosAngeles() throws IOException {
+    SimpleSpatialFieldInfo fieldInfo = new SimpleSpatialFieldInfo("geo");
+    SpatialContext ctx = SimpleSpatialContext.GEO_KM;
+    TermQueryPrefixTreeStrategy prefixGridStrategy = new TermQueryPrefixTreeStrategy(new QuadPrefixTree(ctx));
+
+    Shape point = new PointImpl(-118.243680, 34.052230);
+
+    Document losAngeles = new Document();
+    losAngeles.add(new Field("name", "Los Angeles", StringField.TYPE_STORED));
+    losAngeles.add(prefixGridStrategy.createField(fieldInfo, point, true, true));
+
+    addDocumentsAndCommit(Arrays.asList(losAngeles));
+
+    // This won't work with simple spatial context...
+    SpatialArgsParser spatialArgsParser = new SpatialArgsParser();
+    // TODO... use a non polygon query
+//    SpatialArgs spatialArgs = spatialArgsParser.parse(
+//        "IsWithin(POLYGON((-127.00390625 39.8125,-112.765625 39.98828125,-111.53515625 31.375,-125.94921875 30.14453125,-127.00390625 39.8125)))",
+//        new SimpleSpatialContext());
+
+//    Query query = prefixGridStrategy.makeQuery(spatialArgs, fieldInfo);
+//    SearchResults searchResults = executeQuery(query, 1);
+//    assertEquals(1, searchResults.numFound);
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/vector/BaseTwoDoublesStrategyTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/vector/BaseTwoDoublesStrategyTestCase.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/vector/BaseTwoDoublesStrategyTestCase.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/vector/BaseTwoDoublesStrategyTestCase.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,48 @@
+/*
+ * 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.strategy.vector;
+
+import org.apache.lucene.search.FieldCache;
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.strategy.util.NumericFieldInfo;
+import org.apache.lucene.spatial.SpatialMatchConcern;
+import org.apache.lucene.spatial.StrategyTestCase;
+import org.junit.Test;
+
+import java.io.IOException;
+
+
+public abstract class BaseTwoDoublesStrategyTestCase extends StrategyTestCase<TwoDoublesFieldInfo> {
+
+  protected abstract SpatialContext getSpatialContext();
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    this.ctx = getSpatialContext();
+    this.strategy = new TwoDoublesStrategy(ctx,
+        new NumericFieldInfo(), FieldCache.NUMERIC_UTILS_DOUBLE_PARSER);
+    this.fieldInfo = new TwoDoublesFieldInfo(getClass().getSimpleName());
+  }
+
+  @Test
+  public void testCitiesWithinBBox() throws IOException {
+    getAddAndVerifyIndexedDocuments(DATA_WORLD_CITIES_POINTS);
+    executeQueries(SpatialMatchConcern.FILTER, QTEST_Cities_IsWithin_BBox);
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/vector/TwoDoublesStrategyTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/vector/TwoDoublesStrategyTestCase.java?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/vector/TwoDoublesStrategyTestCase.java (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/java/org/apache/lucene/spatial/strategy/vector/TwoDoublesStrategyTestCase.java Mon Feb 20 22:45:32 2012
@@ -0,0 +1,29 @@
+/*
+ * 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.strategy.vector;
+
+import org.apache.lucene.spatial.base.context.SpatialContext;
+import org.apache.lucene.spatial.base.context.simple.SimpleSpatialContext;
+
+public class TwoDoublesStrategyTestCase extends BaseTwoDoublesStrategyTestCase {
+
+  @Override
+  protected SpatialContext getSpatialContext() {
+    return SimpleSpatialContext.GEO_KM;
+  }
+}

Added: lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/resources/cities-IsWithin-BBox.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/resources/cities-IsWithin-BBox.txt?rev=1291499&view=auto
==============================================================================
--- lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/resources/cities-IsWithin-BBox.txt (added)
+++ lucene/dev/branches/lucene3795_lsp_spatial_module/modules/spatial-lucene/src/test/resources/cities-IsWithin-BBox.txt Mon Feb 20 22:45:32 2012
@@ -0,0 +1,7 @@
+[San Francisco] G5391959 @ IsWithin(-122.524918 37.674973 -122.360123 37.817108)
+[Wellington] G2179537 @ IsWithin(174.711456 -41.360779 174.854279 -41.213837)
+[Barcelona] G6544100 G3128760  @  IsWithin(2.127228 41.333313 2.226105 41.408844)
+
+
+
+