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 2014/01/24 21:16:50 UTC

svn commit: r1561142 [3/3] - in /lucene/dev/branches/branch_4x: ./ lucene/ lucene/benchmark/ lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/feeds/ lucene/licenses/ lucene/spatial/ lucene/spatial/src/java/org/apache/lucene/spatial/query/ l...

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/states-Intersects-BBox.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/states-Intersects-BBox.txt?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/states-Intersects-BBox.txt (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/states-Intersects-BBox.txt Fri Jan 24 20:16:49 2014
@@ -1,3 +1,3 @@
-WY CO	@ Intersects(-106.964844 39.460938 -105.734375 42.800781)
-TX @ Intersects(-99.669922 30.583984 -98.439453 32.253906)
-MS TX LA @ Intersects(-95.363281 29.792969 -90.133789 32.473633)
+WY CO	@ Intersects(ENVELOPE(-106.964844, -105.734375, 42.800781, 39.460938))
+TX @ Intersects(ENVELOPE(-99.669922, -98.439453, 32.253906, 30.583984))
+MS TX LA @ Intersects(ENVELOPE(-95.363281, -90.133789, 32.473633, 29.792969))
\ No newline at end of file

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/states-IsWithin-BBox.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/states-IsWithin-BBox.txt?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/states-IsWithin-BBox.txt (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test-files/states-IsWithin-BBox.txt Fri Jan 24 20:16:49 2014
@@ -1,4 +1,4 @@
-KS	@ IsWithin(-103.493164 36.208984 -93.825195 41.086914)
-WA @ IsWithin(-126.916016 44.36084 -115.314453 50.688965)
-MA CT RI @ IsWithin(-73.894043 40.825195 -69.521484 43.198242)
-AL GA @ IsWithin(-89.472656 29.311523 -80.244141 35.90332)
\ No newline at end of file
+KS	@ IsWithin(ENVELOPE(-103.493164, -93.825195, 41.086914, 36.208984))
+WA @ IsWithin(ENVELOPE(-126.916016, -115.314453, 50.688965, 44.36084))
+MA CT RI @ IsWithin(ENVELOPE(-73.894043, -69.521484, 43.198242, 40.825195))
+AL GA @ IsWithin(ENVELOPE(-89.472656, -80.244141, 35.90332, 29.311523))
\ No newline at end of file

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java Fri Jan 24 20:16:49 2014
@@ -88,8 +88,8 @@ public class DistanceStrategyTest extend
     adoc("103", (Shape)null);//test score for nothing
     commit();
     //FYI distances are in docid order
-    checkDistValueSource("3,4", 2.8274937f, 5.0898066f, 180f);
-    checkDistValueSource("4,0", 3.6043684f, 0.9975641f, 180f);
+    checkDistValueSource(ctx.makePoint(4, 3), 2.8274937f, 5.0898066f, 180f);
+    checkDistValueSource(ctx.makePoint(0, 4), 3.6043684f, 0.9975641f, 180f);
   }
 
   @Test
@@ -115,8 +115,7 @@ public class DistanceStrategyTest extend
   //   return super.newDoc(id, shape);
   // }
 
-  void checkDistValueSource(String ptStr, float... distances) throws IOException {
-    Point pt = (Point) ctx.readShape(ptStr);
+  void checkDistValueSource(Point pt, float... distances) throws IOException {
     float multiplier = random().nextFloat() * 100f;
     float[] dists2 = Arrays.copyOf(distances, distances.length);
     for (int i = 0; i < dists2.length; i++) {

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/PortedSolr3Test.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/PortedSolr3Test.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/PortedSolr3Test.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/PortedSolr3Test.java Fri Jan 24 20:16:49 2014
@@ -36,7 +36,6 @@ import org.apache.lucene.spatial.query.S
 import org.apache.lucene.spatial.vector.PointVectorStrategy;
 import org.junit.Test;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -91,21 +90,21 @@ public class PortedSolr3Test extends Str
     this.strategy = strategy;
   }
 
-  private void setupDocs() throws IOException {
+  private void setupDocs() throws Exception {
     super.deleteAll();
-    adoc("1", "32.7693246, -79.9289094");
-    adoc("2", "33.7693246, -80.9289094");
-    adoc("3", "-32.7693246, 50.9289094");
-    adoc("4", "-50.7693246, 60.9289094");
-    adoc("5", "0,0");
-    adoc("6", "0.1,0.1");
-    adoc("7", "-0.1,-0.1");
-    adoc("8", "0,179.9");
-    adoc("9", "0,-179.9");
-    adoc("10", "89.9,50");
-    adoc("11", "89.9,-130");
-    adoc("12", "-89.9,50");
-    adoc("13", "-89.9,-130");
+    adoc("1", ctx.makePoint(-79.9289094, 32.7693246));
+    adoc("2", ctx.makePoint(-80.9289094, 33.7693246));
+    adoc("3", ctx.makePoint(50.9289094, -32.7693246));
+    adoc("4", ctx.makePoint(60.9289094, -50.7693246));
+    adoc("5", ctx.makePoint(0, 0));
+    adoc("6", ctx.makePoint(0.1, 0.1));
+    adoc("7", ctx.makePoint(-0.1, -0.1));
+    adoc("8", ctx.makePoint(179.9, 0));
+    adoc("9", ctx.makePoint(-179.9, 0));
+    adoc("10", ctx.makePoint(50, 89.9));
+    adoc("11", ctx.makePoint(-130, 89.9));
+    adoc("12", ctx.makePoint(50, -89.9));
+    adoc("13", ctx.makePoint(-130, -89.9));
     commit();
   }
 
@@ -115,53 +114,52 @@ public class PortedSolr3Test extends Str
     setupDocs();
     //Try some edge cases
       //NOTE: 2nd arg is distance in kilometers
-    checkHitsCircle("1,1", 175, 3, 5, 6, 7);
-    checkHitsCircle("0,179.8", 200, 2, 8, 9);
-    checkHitsCircle("89.8, 50", 200, 2, 10, 11);//this goes over the north pole
-    checkHitsCircle("-89.8, 50", 200, 2, 12, 13);//this goes over the south pole
+    checkHitsCircle(ctx.makePoint(1, 1), 175, 3, 5, 6, 7);
+    checkHitsCircle(ctx.makePoint(179.8, 0), 200, 2, 8, 9);
+    checkHitsCircle(ctx.makePoint(50, 89.8), 200, 2, 10, 11);//this goes over the north pole
+    checkHitsCircle(ctx.makePoint(50, -89.8), 200, 2, 12, 13);//this goes over the south pole
     //try some normal cases
-    checkHitsCircle("33.0,-80.0", 300, 2);
+    checkHitsCircle(ctx.makePoint(-80.0, 33.0), 300, 2);
     //large distance
-    checkHitsCircle("1,1", 5000, 3, 5, 6, 7);
+    checkHitsCircle(ctx.makePoint(1, 1), 5000, 3, 5, 6, 7);
     //Because we are generating a box based on the west/east longitudes and the south/north latitudes, which then
     //translates to a range query, which is slightly more inclusive.  Thus, even though 0.0 is 15.725 kms away,
     //it will be included, b/c of the box calculation.
-    checkHitsBBox("0.1,0.1", 15, 2, 5, 6);
+    checkHitsBBox(ctx.makePoint(0.1, 0.1), 15, 2, 5, 6);
     //try some more
     deleteAll();
-    adoc("14", "0,5");
-    adoc("15", "0,15");
+    adoc("14", ctx.makePoint(5, 0));
+    adoc("15", ctx.makePoint(15, 0));
     //3000KM from 0,0, see http://www.movable-type.co.uk/scripts/latlong.html
-    adoc("16", "18.71111,19.79750");
-    adoc("17", "44.043900,-95.436643");
+    adoc("16", ctx.makePoint(19.79750, 18.71111));
+    adoc("17", ctx.makePoint(-95.436643, 44.043900));
     commit();
 
-    checkHitsCircle("0,0", 1000, 1, 14);
-    checkHitsCircle("0,0", 2000, 2, 14, 15);
-    checkHitsBBox("0,0", 3000, 3, 14, 15, 16);
-    checkHitsCircle("0,0", 3001, 3, 14, 15, 16);
-    checkHitsCircle("0,0", 3000.1, 3, 14, 15, 16);
+    checkHitsCircle(ctx.makePoint(0, 0), 1000, 1, 14);
+    checkHitsCircle(ctx.makePoint(0, 0), 2000, 2, 14, 15);
+    checkHitsBBox(ctx.makePoint(0, 0), 3000, 3, 14, 15, 16);
+    checkHitsCircle(ctx.makePoint(0, 0), 3001, 3, 14, 15, 16);
+    checkHitsCircle(ctx.makePoint(0, 0), 3000.1, 3, 14, 15, 16);
 
     //really fine grained distance and reflects some of the vagaries of how we are calculating the box
-    checkHitsCircle("43.517030,-96.789603", 109, 0);
+    checkHitsCircle(ctx.makePoint(-96.789603, 43.517030), 109, 0);
 
     // falls outside of the real distance, but inside the bounding box
-    checkHitsCircle("43.517030,-96.789603", 110, 0);
-    checkHitsBBox("43.517030,-96.789603", 110, 1, 17);
+    checkHitsCircle(ctx.makePoint(-96.789603, 43.517030), 110, 0);
+    checkHitsBBox(ctx.makePoint(-96.789603, 43.517030), 110, 1, 17);
   }
 
   //---- these are similar to Solr test methods
 
-  private void checkHitsCircle(String ptStr, double distKM, int assertNumFound, int... assertIds) {
-    _checkHits(false, ptStr, distKM, assertNumFound, assertIds);
+  private void checkHitsCircle(Point pt, double distKM, int assertNumFound, int... assertIds) {
+    _checkHits(false, pt, distKM, assertNumFound, assertIds);
   }
-  private void checkHitsBBox(String ptStr, double distKM, int assertNumFound, int... assertIds) {
-    _checkHits(true, ptStr, distKM, assertNumFound, assertIds);
+  private void checkHitsBBox(Point pt, double distKM, int assertNumFound, int... assertIds) {
+    _checkHits(true, pt, distKM, assertNumFound, assertIds);
   }
 
-  private void _checkHits(boolean bbox, String ptStr, double distKM, int assertNumFound, int... assertIds) {
+  private void _checkHits(boolean bbox, Point pt, double distKM, int assertNumFound, int... assertIds) {
     SpatialOperation op = SpatialOperation.Intersects;
-    Point pt = (Point) ctx.readShape(ptStr);
     double distDEG = DistanceUtils.dist2Degrees(distKM, DistanceUtils.EARTH_MEAN_RADIUS_KM);
     Shape shape = ctx.makeCircle(pt, distDEG);
     if (bbox)

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java Fri Jan 24 20:16:49 2014
@@ -57,11 +57,11 @@ public class SpatialExample extends Luce
 
   //Note: Test invoked via TestTestFramework.spatialExample()
 
-  public static void main(String[] args) throws IOException {
+  public static void main(String[] args) throws Exception {
     new SpatialExample().test();
   }
 
-  public void test() throws IOException {
+  public void test() throws Exception {
     init();
     indexPoints();
     search();
@@ -102,7 +102,7 @@ public class SpatialExample extends Luce
     this.directory = new RAMDirectory();
   }
 
-  private void indexPoints() throws IOException {
+  private void indexPoints() throws Exception {
     IndexWriterConfig iwConfig = new IndexWriterConfig(TEST_VERSION_CURRENT,null);
     IndexWriter indexWriter = new IndexWriter(directory, iwConfig);
 
@@ -110,10 +110,9 @@ public class SpatialExample extends Luce
     indexWriter.addDocument(newSampleDocument(
         2, ctx.makePoint(-80.93, 33.77)));
 
-    //When parsing a string to a shape, the presence of a comma means it's y-x
-    // order (lon, lat)
+    //Spatial4j has a WKT parser which is also "x y" order
     indexWriter.addDocument(newSampleDocument(
-        4, ctx.readShape("-50.7693246, 60.9289094")));
+        4, ctx.readShapeFromWkt("POINT(60.9289094 -50.7693246)")));
 
     indexWriter.addDocument(newSampleDocument(
         20, ctx.makePoint(0.1,0.1), ctx.makePoint(0, 0)));
@@ -131,13 +130,15 @@ public class SpatialExample extends Luce
         doc.add(f);
       }
       //store it too; the format is up to you
-      doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
+      //  (assume point in this example)
+      Point pt = (Point) shape;
+      doc.add(new StoredField(strategy.getFieldName(), pt.getX()+" "+pt.getY()));
     }
 
     return doc;
   }
 
-  private void search() throws IOException {
+  private void search() throws Exception {
     IndexReader indexReader = DirectoryReader.open(directory);
     IndexSearcher indexSearcher = new IndexSearcher(indexReader);
     Sort idSort = new Sort(new SortField("id", SortField.Type.INT));
@@ -155,15 +156,19 @@ public class SpatialExample extends Luce
       // (this computation is usually not redundant)
       Document doc1 = indexSearcher.doc(docs.scoreDocs[0].doc);
       String doc1Str = doc1.getField(strategy.getFieldName()).stringValue();
-      Point doc1Point = (Point) ctx.readShape(doc1Str);
-      double doc1DistDEG = ctx.getDistCalc().distance(args.getShape().getCenter(), doc1Point);
+      //assume doc1Str is "x y" as written in newSampleDocument()
+      int spaceIdx = doc1Str.indexOf(' ');
+      double x = Double.parseDouble(doc1Str.substring(0, spaceIdx));
+      double y = Double.parseDouble(doc1Str.substring(spaceIdx+1));
+      double doc1DistDEG = ctx.calcDistance(args.getShape().getCenter(), x, y);
       assertEquals(121.6d, DistanceUtils.degrees2Dist(doc1DistDEG, DistanceUtils.EARTH_MEAN_RADIUS_KM), 0.1);
+      //or more simply:
+      assertEquals(121.6d, doc1DistDEG * DistanceUtils.DEG_TO_KM, 0.1);
     }
     //--Match all, order by distance ascending
     {
       Point pt = ctx.makePoint(60, -50);
-      double degToKm = DistanceUtils.degrees2Dist(1, DistanceUtils.EARTH_MEAN_RADIUS_KM);
-      ValueSource valueSource = strategy.makeDistanceValueSource(pt, degToKm);//the distance (in km)
+      ValueSource valueSource = strategy.makeDistanceValueSource(pt, DistanceUtils.DEG_TO_KM);//the distance (in km)
       Sort distSort = new Sort(valueSource.getSortField(false)).rewrite(indexSearcher);//false=asc dist
       TopDocs docs = indexSearcher.search(new MatchAllDocsQuery(), 10, distSort);
       assertDocMatchedIds(indexSearcher, docs, 4, 20, 2);
@@ -178,7 +183,7 @@ public class SpatialExample extends Luce
     {
       SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects,
           ctx.makeCircle(-80.0, 33.0, 1));
-      SpatialArgs args2 = new SpatialArgsParser().parse("Intersects(Circle(33,-80 d=1))", ctx);
+      SpatialArgs args2 = new SpatialArgsParser().parse("Intersects(BUFFER(POINT(-80 33),1))", ctx);
       assertEquals(args.toString(),args2.toString());
     }
 

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestQuery.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestQuery.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestQuery.java Fri Jan 24 20:16:49 2014
@@ -18,10 +18,10 @@ package org.apache.lucene.spatial;
  */
 
 import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.io.LineReader;
 import org.apache.lucene.spatial.query.SpatialArgs;
 import org.apache.lucene.spatial.query.SpatialArgsParser;
 
+import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -41,20 +41,23 @@ public class SpatialTestQuery {
   public List<String> ids = new ArrayList<String>();
 
   /**
-   * Get Test Queries
+   * Get Test Queries.  The InputStream is closed.
    */
   public static Iterator<SpatialTestQuery> getTestQueries(
       final SpatialArgsParser parser,
       final SpatialContext ctx,
       final String name,
       final InputStream in ) throws IOException {
-    return new LineReader<SpatialTestQuery>(new InputStreamReader(in,"UTF-8")) {
 
-      @Override
-      public SpatialTestQuery parseLine(String line) {
+    List<SpatialTestQuery> results = new ArrayList<SpatialTestQuery>();
+
+    BufferedReader bufInput = new BufferedReader(new InputStreamReader(in,"UTF-8"));
+    try {
+      String line;
+      for (int lineNumber = 1; (line = bufInput.readLine()) != null; lineNumber++) {
         SpatialTestQuery test = new SpatialTestQuery();
         test.line = line;
-        test.lineNumber = getLineNumber();
+        test.lineNumber = lineNumber;
 
         try {
           // skip a comment
@@ -71,13 +74,16 @@ public class SpatialTestQuery {
             test.ids.add(st.nextToken().trim());
           }
           test.args = parser.parse(line.substring(idx + 1).trim(), ctx);
-          return test;
+          results.add(test);
         }
         catch( Exception ex ) {
           throw new RuntimeException( "invalid query line: "+test.line, ex );
         }
       }
-    };
+    } finally {
+      bufInput.close();
+    }
+    return results.iterator();
   }
 
   @Override

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/StrategyTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/StrategyTestCase.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/StrategyTestCase.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/StrategyTestCase.java Fri Jan 24 20:16:49 2014
@@ -19,8 +19,6 @@ package org.apache.lucene.spatial;
  */
 
 import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.io.sample.SampleData;
-import com.spatial4j.core.io.sample.SampleDataReader;
 import com.spatial4j.core.shape.Shape;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
@@ -41,6 +39,7 @@ import org.junit.Assert;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -87,21 +86,21 @@ public abstract class StrategyTestCase e
     return getDocuments(getSampleData(testDataFile));
   }
 
-  protected List<Document> getDocuments(Iterator<SampleData> sampleData) {
+  protected List<Document> getDocuments(Iterator<SpatialTestData> sampleData) {
     List<Document> documents = new ArrayList<Document>();
     while (sampleData.hasNext()) {
-      SampleData data = sampleData.next();
+      SpatialTestData data = sampleData.next();
       Document document = new Document();
       document.add(new StringField("id", data.id, Field.Store.YES));
       document.add(new StringField("name", data.name, Field.Store.YES));
-      Shape shape = ctx.readShape(data.shape);
+      Shape shape = data.shape;
       shape = convertShapeFromGetDocuments(shape);
       if (shape != null) {
         for (Field f : strategy.createIndexableFields(shape)) {
           document.add(f);
         }
-        if (storeShape)
-          document.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
+        if (storeShape)//just for diagnostics
+          document.add(new StoredField(strategy.getFieldName(), shape.toString()));
       }
 
       documents.add(document);
@@ -114,18 +113,18 @@ public abstract class StrategyTestCase e
     return shape;
   }
 
-  protected Iterator<SampleData> getSampleData(String testDataFile) throws IOException {
+  protected Iterator<SpatialTestData> getSampleData(String testDataFile) throws IOException {
     String path = "data/" + testDataFile;
     InputStream stream = getClass().getClassLoader().getResourceAsStream(path);
     if (stream == null)
       throw new FileNotFoundException("classpath resource not found: "+path);
-    return new SampleDataReader(stream);
+    return SpatialTestData.getTestData(stream, ctx);//closes the InputStream
   }
 
   protected Iterator<SpatialTestQuery> getTestQueries(String testQueryFile, SpatialContext ctx) throws IOException {
     InputStream in = getClass().getClassLoader().getResourceAsStream(testQueryFile);
     return SpatialTestQuery.getTestQueries(
-        argsParser, ctx, testQueryFile, in );
+        argsParser, ctx, testQueryFile, in );//closes the InputStream
   }
 
   public void runTestQueries(
@@ -141,8 +140,8 @@ public abstract class StrategyTestCase e
     String msg = q.toString(); //"Query: " + q.args.toString(ctx);
     SearchResults got = executeQuery(strategy.makeQuery(q.args), Math.max(100, q.ids.size()+1));
     if (storeShape && got.numFound > 0) {
-      //check stored value is there & parses
-      assertNotNull(ctx.readShape(got.results.get(0).document.get(strategy.getFieldName())));
+      //check stored value is there
+      assertNotNull(got.results.get(0).document.get(strategy.getFieldName()));
     }
     if (concern.orderIsImportant) {
       Iterator<String> ids = q.ids.iterator();
@@ -183,8 +182,8 @@ public abstract class StrategyTestCase e
     }
   }
 
-  protected void adoc(String id, String shapeStr) throws IOException {
-    Shape shape = shapeStr==null ? null : ctx.readShape(shapeStr);
+  protected void adoc(String id, String shapeStr) throws IOException, ParseException {
+    Shape shape = shapeStr==null ? null : ctx.readShapeFromWkt(shapeStr);
     addDocument(newDoc(id, shape));
   }
   protected void adoc(String id, Shape shape) throws IOException {
@@ -199,7 +198,7 @@ public abstract class StrategyTestCase e
         doc.add(f);
       }
       if (storeShape)
-        doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
+        doc.add(new StoredField(strategy.getFieldName(), shape.toString()));//not to be parsed; just for debug
     }
     return doc;
   }

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/TestTestFramework.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/TestTestFramework.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/TestTestFramework.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/TestTestFramework.java Fri Jan 24 20:16:49 2014
@@ -44,7 +44,7 @@ public class TestTestFramework extends L
     InputStream in = getClass().getClassLoader().getResourceAsStream(name);
     SpatialContext ctx = SpatialContext.GEO;
     Iterator<SpatialTestQuery> iter = SpatialTestQuery.getTestQueries(
-        new SpatialArgsParser(), ctx, name, in );
+        new SpatialArgsParser(), ctx, name, in );//closes the InputStream
     List<SpatialTestQuery> tests = new ArrayList<SpatialTestQuery>();
     while( iter.hasNext() ) {
       tests.add( iter.next() );
@@ -52,15 +52,15 @@ public class TestTestFramework extends L
     Assert.assertEquals( 3, tests.size() );
 
     SpatialTestQuery sf = tests.get(0);
-   // assert
+    // 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.Intersects, sf.args.getOperation() );
+    Assert.assertEquals(SpatialOperation.Intersects, sf.args.getOperation());
   }
 
   @Test
-  public void spatialExample() throws IOException {
+  public void spatialExample() throws Exception {
     //kind of a hack so that SpatialExample is tested despite
     // it not starting or ending with "Test".
     SpatialExample.main(null);

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/JtsPolygonTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/JtsPolygonTest.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/JtsPolygonTest.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/JtsPolygonTest.java Fri Jan 24 20:16:49 2014
@@ -35,7 +35,7 @@ import org.apache.lucene.spatial.query.S
 import org.apache.lucene.spatial.query.SpatialOperation;
 import org.junit.Test;
 
-import java.io.IOException;
+import java.text.ParseException;
 import java.util.HashMap;
 
 public class JtsPolygonTest extends StrategyTestCase {
@@ -59,7 +59,7 @@ public class JtsPolygonTest extends Stra
 
   @Test
   /** LUCENE-4464 */
-  public void testCloseButNoMatch() throws IOException {
+  public void testCloseButNoMatch() throws Exception {
     getAddAndVerifyIndexedDocuments("LUCENE-4464.txt");
     SpatialArgs args = q(
         "POLYGON((-93.18100824442227 45.25676372469945," +
@@ -73,8 +73,8 @@ public class JtsPolygonTest extends Stra
     //did not find poly 1 !
   }
 
-  private SpatialArgs q(String shapeStr, double distErrPct) {
-    Shape shape = ctx.readShape(shapeStr);
+  private SpatialArgs q(String shapeStr, double distErrPct) throws ParseException {
+    Shape shape = ctx.readShapeFromWkt(shapeStr);
     SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, shape);
     args.setDistErrPct(distErrPct);
     return args;
@@ -87,7 +87,7 @@ public class JtsPolygonTest extends Stra
   @Test
   public void testBadPrefixTreePrune() throws Exception {
   
-    Shape area = ctx.readShape("POLYGON((-122.83 48.57, -122.77 48.56, -122.79 48.53, -122.83 48.57))");
+    Shape area = ctx.readShapeFromWkt("POLYGON((-122.83 48.57, -122.77 48.56, -122.79 48.53, -122.83 48.57))");
     
     SpatialPrefixTree trie = new QuadPrefixTree(ctx, 12);
     TermQueryPrefixTreeStrategy strategy = new TermQueryPrefixTreeStrategy(trie, "geo");

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/SpatialOpRecursivePrefixTreeTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/SpatialOpRecursivePrefixTreeTest.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/SpatialOpRecursivePrefixTreeTest.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/SpatialOpRecursivePrefixTreeTest.java Fri Jan 24 20:16:49 2014
@@ -19,6 +19,7 @@ package org.apache.lucene.spatial.prefix
 
 import com.carrotsearch.randomizedtesting.annotations.Repeat;
 import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.context.SpatialContextFactory;
 import com.spatial4j.core.shape.Point;
 import com.spatial4j.core.shape.Rectangle;
 import com.spatial4j.core.shape.Shape;
@@ -71,7 +72,10 @@ public class SpatialOpRecursivePrefixTre
   public void mySetup(int maxLevels) throws IOException {
     //non-geospatial makes this test a little easier (in gridSnap), and using boundary values 2^X raises
     // the prospect of edge conditions we want to test, plus makes for simpler numbers (no decimals).
-    this.ctx = new SpatialContext(false, null, new RectangleImpl(0, 256, -128, 128, null));
+    SpatialContextFactory factory = new SpatialContextFactory();
+    factory.geo = false;
+    factory.worldBounds = new RectangleImpl(0, 256, -128, 128, null);
+    this.ctx = factory.newSpatialContext();
     //A fairly shallow grid, and default 2.5% distErrPct
     if (maxLevels == -1)
       maxLevels = randomIntBetween(1, 8);
@@ -179,8 +183,8 @@ public class SpatialOpRecursivePrefixTre
           doc.add(f);
         }
       }
-      if (storeShape)
-        doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
+      if (storeShape)//just for diagnostics
+        doc.add(new StoredField(strategy.getFieldName(), shape.toString()));
     }
     return doc;
   }
@@ -412,6 +416,16 @@ public class SpatialOpRecursivePrefixTre
     }
 
     @Override
+    public Shape getBuffered(double distance, SpatialContext ctx) {
+      throw new UnsupportedOperationException("TODO unimplemented");//TODO
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return false;
+    }
+
+    @Override
     public String toString() {
       return "ShapePair(" + shape1 + " , " + shape2 + ")";
     }

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/TestTermQueryPrefixGridStrategy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/TestTermQueryPrefixGridStrategy.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/TestTermQueryPrefixGridStrategy.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/TestTermQueryPrefixGridStrategy.java Fri Jan 24 20:16:49 2014
@@ -47,7 +47,7 @@ public class TestTermQueryPrefixGridStra
     for (IndexableField field : prefixGridStrategy.createIndexableFields(point)) {
       losAngeles.add(field);
     }
-    losAngeles.add(new StoredField(prefixGridStrategy.getFieldName(), ctx.toString(point)));
+    losAngeles.add(new StoredField(prefixGridStrategy.getFieldName(), point.toString()));//just for diagnostics
 
     addDocumentsAndCommit(Arrays.asList(losAngeles));
 

Modified: lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java (original)
+++ lucene/dev/branches/branch_4x/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java Fri Jan 24 20:16:49 2014
@@ -34,7 +34,7 @@ public class SpatialArgsParserTest exten
   public void testArgsParser() throws Exception {
     SpatialArgsParser parser = new SpatialArgsParser();
 
-    String arg = SpatialOperation.IsWithin + "(-10 -20 10 20)";
+    String arg = SpatialOperation.IsWithin + "(Envelope(-10, 10, 20, -20))";
     SpatialArgs out = parser.parse(arg, ctx);
     assertEquals(SpatialOperation.IsWithin, out.getOperation());
     Rectangle bounds = (Rectangle) out.getShape();
@@ -42,7 +42,7 @@ public class SpatialArgsParserTest exten
     assertEquals(10.0, bounds.getMaxX(), 0D);
 
     // Disjoint should not be scored
-    arg = SpatialOperation.IsDisjointTo + " (-10 10 -20 20)";
+    arg = SpatialOperation.IsDisjointTo + " (Envelope(-10,-20,20,10))";
     out = parser.parse(arg, ctx);
     assertEquals(SpatialOperation.IsDisjointTo, out.getOperation());
 
@@ -54,7 +54,7 @@ public class SpatialArgsParserTest exten
     }
 
     try {
-      parser.parse("XXXX(-10 10 -20 20)", ctx);
+      parser.parse("XXXX(Envelope(-10, 10, 20, -20))", ctx);
       fail("unknown operation!");
     }
     catch (Exception ex) {//expected

Modified: lucene/dev/branches/branch_4x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/CHANGES.txt?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_4x/solr/CHANGES.txt Fri Jan 24 20:16:49 2014
@@ -79,8 +79,8 @@ New Features
 * SOLR-5506: Support docValues in CollationField and ICUCollationField.
   (Robert Muir)
   
- * SOLR-5518: Added EditFileRequestHandler to deal with security issues around modifying
-   solr configuration files.
+* SOLR-5518: Added EditFileRequestHandler to deal with security issues around modifying
+  solr configuration files.
 
 * SOLR-5023: Add support for deleteInstanceDir to be passed from SolrJ for Core
   Unload action. (Lyubov Romanchuk, shalin)
@@ -123,6 +123,10 @@ New Features
 * SOLR-5594: Allow FieldTypes to specify custom PrefixQuery behavior
   (Anshum Gupta via hossman)
 
+* LUCENE-5395: Upgrade to Spatial4j 0.4. Various new options are now exposed
+  automatically for an RPT field type.  See Spatial4j CHANGES & javadocs.
+  https://github.com/spatial4j/spatial4j/blob/master/CHANGES.md  (David Smiley)
+
 Bug Fixes
 ----------------------
 

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java Fri Jan 24 20:16:49 2014
@@ -17,15 +17,16 @@ package org.apache.solr.schema;
  * limitations under the License.
  */
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
+import com.google.common.base.Throwables;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.context.SpatialContextFactory;
+import com.spatial4j.core.distance.DistanceUtils;
+import com.spatial4j.core.io.LegacyShapeReadWriterFormat;
+import com.spatial4j.core.shape.Point;
+import com.spatial4j.core.shape.Rectangle;
+import com.spatial4j.core.shape.Shape;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.StoredField;
 import org.apache.lucene.index.IndexableField;
@@ -45,20 +46,19 @@ import org.apache.solr.response.TextResp
 import org.apache.solr.search.QParser;
 import org.apache.solr.search.SpatialOptions;
 import org.apache.solr.util.MapListener;
+import org.apache.solr.util.SpatialUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Throwables;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.context.SpatialContextFactory;
-import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.exception.InvalidShapeException;
-import com.spatial4j.core.io.ParseUtils;
-import com.spatial4j.core.shape.Point;
-import com.spatial4j.core.shape.Rectangle;
-import com.spatial4j.core.shape.Shape;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 
 /**
  * Abstract base class for Solr FieldTypes based on a Lucene 4 {@link SpatialStrategy}.
@@ -90,12 +90,32 @@ public abstract class AbstractSpatialFie
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
           "Must specify units=\"degrees\" on field types with class "+getClass().getSimpleName());
 
+    //replace legacy rect format with ENVELOPE
+    String wbStr = args.get("worldBounds");
+    if (wbStr != null && !wbStr.toUpperCase().startsWith("ENVELOPE")) {
+      log.warn("Using old worldBounds format? Should use ENVELOPE(xMin, xMax, yMax, yMin).");
+      String[] parts = wbStr.split(" ");//"xMin yMin xMax yMax"
+      if (parts.length == 4) {
+        args.put("worldBounds",
+            "ENVELOPE(" + parts[0] + ", " + parts[2] + ", " + parts[3] + ", " + parts[1] + ")");
+      } //else likely eventual exception
+    }
+
     //Solr expects us to remove the parameters we've used.
     MapListener<String, String> argsWrap = new MapListener<String, String>(args);
     ctx = SpatialContextFactory.makeSpatialContext(argsWrap, schema.getResourceLoader().getClassLoader());
     args.keySet().removeAll(argsWrap.getSeenKeys());
 
-    argsParser = new SpatialArgsParser();//might make pluggable some day?
+    argsParser = newSpatialArgsParser();
+  }
+
+  protected SpatialArgsParser newSpatialArgsParser() {
+    return new SpatialArgsParser() {
+      @Override
+      protected Shape parseShape(String str, SpatialContext ctx) throws ParseException {
+        return AbstractSpatialFieldType.this.parseShape(str);
+      }
+    };
   }
 
   //--------------------------------------------------------------
@@ -137,16 +157,39 @@ public abstract class AbstractSpatialFie
     return result;
   }
 
-  protected Shape parseShape(String shapeStr) {
+  protected Shape parseShape(String str) {
+    if (str.length() == 0)
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "empty string shape");
+    //In Solr trunk we only support "lat, lon" (or x y) as an additional format; in v4.0 we do the
+    // weird Circle & Rect formats too (Spatial4j LegacyShapeReadWriterFormat).
     try {
-      return ctx.readShape(shapeStr);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
+      Shape shape = LegacyShapeReadWriterFormat.readShapeOrNull(str, ctx);
+      if (shape != null)
+        return shape;
+      return ctx.readShapeFromWkt(str);
+    } catch (Exception e) {
+      String message = e.getMessage();
+      if (!message.contains(str))
+        message = "Couldn't parse shape '" + str + "' because: " + message;
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message, e);
     }
   }
 
+  /**
+   * Returns a String version of a shape to be used for the stored value. This method in Solr is only called if for some
+   * reason a Shape object is passed to the field type (perhaps via a custom UpdateRequestProcessor),
+   * *and* the field is marked as stored.  <em>The default implementation throws an exception.</em>
+   * <p/>
+   * Spatial4j 0.4 is probably the last release to support SpatialContext.toString(shape) but it's deprecated with no
+   * planned replacement.  Shapes do have a toString() method but they are generally internal/diagnostic and not
+   * standard WKT.
+   * The solution is subclassing and calling ctx.toString(shape) or directly using LegacyShapeReadWriterFormat or
+   * passing in some sort of custom wrapped shape that holds a reference to a String or can generate it.
+   */
   protected String shapeToString(Shape shape) {
-    return ctx.toString(shape);
+//    return ctx.toString(shape);
+    throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+        "Getting a String from a Shape is no longer possible. See javadocs for commentary.");
   }
 
   /** Called from {@link #getStrategy(String)} upon first use by fieldName. } */
@@ -162,27 +205,16 @@ public abstract class AbstractSpatialFie
   //--------------------------------------------------------------
 
   /**
-   * Implemented for compatibility with Solr 3 spatial geofilt & bbox query parsers:
+   * Implemented for compatibility with geofilt & bbox query parsers:
    * {@link SpatialQueryable}.
    */
   @Override
   public Query createSpatialQuery(QParser parser, SpatialOptions options) {
-    //--WARNING: the code from here to the next marker is identical to LatLonType's impl.
-    double[] point = null;
-    try {
-      point = ParseUtils.parseLatitudeLongitude(options.pointStr);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
-
-    // lat & lon in degrees
-    double latCenter = point[0];
-    double lonCenter = point[1];
+    Point pt = SpatialUtils.parsePointSolrException(options.pointStr, ctx);
 
     double distDeg = DistanceUtils.dist2Degrees(options.distance, options.radius);
-    //--END-WARNING
 
-    Shape shape = ctx.makeCircle(lonCenter, latCenter, distDeg);
+    Shape shape = ctx.makeCircle(pt, distDeg);
     if (options.bbox)
       shape = shape.getBoundingBox();
 
@@ -194,12 +226,9 @@ public abstract class AbstractSpatialFie
   public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
     if (!minInclusive || !maxInclusive)
       throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Both sides of spatial range query must be inclusive: " + field.getName());
-    Shape shape1 = parseShape(part1);
-    Shape shape2 = parseShape(part2);
-    if (!(shape1 instanceof Point) || !(shape2 instanceof Point))
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Both sides of spatial range query must be points: " + field.getName());
-    Point p1 = (Point) shape1;
-    Point p2 = (Point) shape2;
+    Point p1 = SpatialUtils.parsePointSolrException(part1, ctx);
+    Point p2 = SpatialUtils.parsePointSolrException(part2, ctx);
+
     Rectangle bbox = ctx.makeRectangle(p1, p2);
     SpatialArgs spatialArgs = new SpatialArgs(SpatialOperation.Intersects, bbox);
     return getQueryFromSpatialArgs(parser, field, spatialArgs);//won't score by default
@@ -221,6 +250,8 @@ public abstract class AbstractSpatialFie
   protected SpatialArgs parseSpatialArgs(String externalVal) {
     try {
       return argsParser.parse(externalVal, ctx);
+    } catch (SolrException e) {
+      throw e;
     } catch (Exception e) {
       throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
     }

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/GeoHashField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/GeoHashField.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/GeoHashField.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/GeoHashField.java Fri Jan 24 20:16:49 2014
@@ -22,18 +22,16 @@ import org.apache.lucene.queries.functio
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.SortField;
-import com.spatial4j.core.io.ParseUtils;
 import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.exception.InvalidShapeException;
 import com.spatial4j.core.io.GeohashUtils;
 import com.spatial4j.core.shape.Point;
-import org.apache.solr.common.SolrException;
 import org.apache.solr.response.TextResponseWriter;
 import org.apache.solr.search.QParser;
 import org.apache.solr.search.SolrConstantScoreQuery;
 import org.apache.solr.search.SpatialOptions;
 import org.apache.solr.search.function.ValueSourceRangeFilter;
 import org.apache.solr.search.function.distance.GeohashHaversineFunction;
+import org.apache.solr.util.SpatialUtils;
 
 
 import java.io.IOException;
@@ -42,14 +40,9 @@ import java.io.IOException;
  * This is a class that represents a <a
  * href="http://en.wikipedia.org/wiki/Geohash">Geohash</a> field. The field is
  * provided as a lat/lon pair and is internally represented as a string.
- *
- * @see com.spatial4j.core.io.ParseUtils#parseLatitudeLongitude(double[], String)
  */
 public class GeoHashField extends FieldType implements SpatialQueryable {
 
-
-  private final SpatialContext ctx = SpatialContext.GEO;
-
   @Override
   public SortField getSortField(SchemaField field, boolean top) {
     return getStringSort(field, top);
@@ -60,13 +53,7 @@ public class GeoHashField extends FieldT
   //encoding.  Plus there are issues around the Equator/Prime Meridian
   @Override
   public Query createSpatialQuery(QParser parser, SpatialOptions options) {
-    double [] point = new double[0];
-    try {
-      point = ParseUtils.parsePointDouble(null, options.pointStr, 2);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
-    String geohash = GeohashUtils.encodeLatLon(point[0], point[1]);
+    String geohash = toInternal(options.pointStr);
     //TODO: optimize this
     return new SolrConstantScoreQuery(new ValueSourceRangeFilter(new GeohashHaversineFunction(getValueSource(options.field, parser),
             new LiteralValueSource(geohash), options.radius), "0", String.valueOf(options.distance), true, true));
@@ -78,33 +65,22 @@ public class GeoHashField extends FieldT
     writer.writeStr(name, toExternal(f), false);
   }
 
-
   @Override
   public String toExternal(IndexableField f) {
-    Point p = GeohashUtils.decode(f.stringValue(),ctx);
+    Point p = GeohashUtils.decode(f.stringValue(), SpatialContext.GEO);
     return p.getY() + "," + p.getX();
   }
 
-
   @Override
   public String toInternal(String val) {
-    // validate that the string is of the form
-    // latitude, longitude
-    double[] latLon = new double[0];
-    try {
-      latLon = ParseUtils.parseLatitudeLongitude(null, val);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
-    return GeohashUtils.encodeLatLon(latLon[0], latLon[1]);
+    Point point = SpatialUtils.parsePointSolrException(val, SpatialContext.GEO);
+    return GeohashUtils.encodeLatLon(point.getY(), point.getX());
   }
 
-
   @Override
   public ValueSource getValueSource(SchemaField field, QParser parser) {
     field.checkFieldCacheSource(parser);
     return new StrFieldSource(field.name);
   }
 
-
 }

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/LatLonType.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/LatLonType.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/LatLonType.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/LatLonType.java Fri Jan 24 20:16:49 2014
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import com.spatial4j.core.shape.Point;
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.index.AtomicReaderContext;
@@ -49,9 +50,8 @@ import org.apache.solr.search.SpatialOpt
 
 import com.spatial4j.core.context.SpatialContext;
 import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.exception.InvalidShapeException;
-import com.spatial4j.core.io.ParseUtils;
 import com.spatial4j.core.shape.Rectangle;
+import org.apache.solr.util.SpatialUtils;
 
 
 /**
@@ -71,24 +71,16 @@ public class LatLonType extends Abstract
   @Override
   public List<IndexableField> createFields(SchemaField field, Object value, float boost) {
     String externalVal = value.toString();
-    //we could have tileDiff + 3 fields (two for the lat/lon, one for storage)
+    //we could have 3 fields (two for the lat & lon, one for storage)
     List<IndexableField> f = new ArrayList<IndexableField>(3);
     if (field.indexed()) {
-      int i = 0;
-      double[] latLon;
-      try {
-        latLon = ParseUtils.parseLatitudeLongitude(null, externalVal);
-      } catch (InvalidShapeException e) {
-        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-      }
+      Point point = SpatialUtils.parsePointSolrException(externalVal, SpatialContext.GEO);
       //latitude
-      SchemaField lat = subField(field, i, schema);
-      f.add(lat.createField(String.valueOf(latLon[LAT]), lat.indexed() && !lat.omitNorms() ? boost : 1f));
-      i++;
+      SchemaField subLatSF = subField(field, LAT, schema);
+      f.add(subLatSF.createField(String.valueOf(point.getY()), subLatSF.indexed() && !subLatSF.omitNorms() ? boost : 1f));
       //longitude
-      SchemaField lon = subField(field, i, schema);
-      f.add(lon.createField(String.valueOf(latLon[LON]), lon.indexed() && !lon.omitNorms() ? boost : 1f));
-
+      SchemaField subLonSF = subField(field, LON, schema);
+      f.add(subLonSF.createField(String.valueOf(point.getX()), subLonSF.indexed() && !subLonSF.omitNorms() ? boost : 1f));
     }
 
     if (field.stored()) {
@@ -102,59 +94,43 @@ public class LatLonType extends Abstract
 
   @Override
   public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
-    int dimension = 2;
+    Point p1 = SpatialUtils.parsePointSolrException(part1, SpatialContext.GEO);
+    Point p2 = SpatialUtils.parsePointSolrException(part2, SpatialContext.GEO);
 
-    String[] p1;
-    String[] p2;
-    try {
-      p1 = ParseUtils.parsePoint(null, part1, dimension);
-      p2 = ParseUtils.parsePoint(null, part2, dimension);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
+    SchemaField latSF = subField(field, LAT, parser.getReq().getSchema());
+    SchemaField lonSF = subField(field, LON, parser.getReq().getSchema());
     BooleanQuery result = new BooleanQuery(true);
-    for (int i = 0; i < dimension; i++) {
-      SchemaField subSF = subField(field, i, parser.getReq().getSchema());
-      // points must currently be ordered... should we support specifying any two opposite corner points?
-      result.add(subSF.getType().getRangeQuery(parser, subSF, p1[i], p2[i], minInclusive, maxInclusive), BooleanClause.Occur.MUST);
-    }
+    // points must currently be ordered... should we support specifying any two opposite corner points?
+    result.add(latSF.getType().getRangeQuery(parser, latSF,
+        Double.toString(p1.getY()), Double.toString(p2.getY()), minInclusive, maxInclusive), BooleanClause.Occur.MUST);
+    result.add(lonSF.getType().getRangeQuery(parser, lonSF,
+        Double.toString(p1.getX()), Double.toString(p2.getX()), minInclusive, maxInclusive), BooleanClause.Occur.MUST);
     return result;
-
   }
 
   @Override
   public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {
-    int dimension = 2;
-    
-    String[] p1 = new String[0];
-    try {
-      p1 = ParseUtils.parsePoint(null, externalVal, dimension);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
-    BooleanQuery bq = new BooleanQuery(true);
-    for (int i = 0; i < dimension; i++) {
-      SchemaField sf = subField(field, i, parser.getReq().getSchema());
-      Query tq = sf.getType().getFieldQuery(parser, sf, p1[i]);
-      bq.add(tq, BooleanClause.Occur.MUST);
-    }
-    return bq;
+    Point p1 = SpatialUtils.parsePointSolrException(externalVal, SpatialContext.GEO);
+
+    SchemaField latSF = subField(field, LAT, parser.getReq().getSchema());
+    SchemaField lonSF = subField(field, LON, parser.getReq().getSchema());
+    BooleanQuery result = new BooleanQuery(true);
+    result.add(latSF.getType().getFieldQuery(parser, latSF,
+        Double.toString(p1.getY())), BooleanClause.Occur.MUST);
+    result.add(lonSF.getType().getFieldQuery(parser, lonSF,
+        Double.toString(p1.getX())), BooleanClause.Occur.MUST);
+    return result;
   }
 
 
 
   @Override
   public Query createSpatialQuery(QParser parser, SpatialOptions options) {
-    double[] point = null;
-    try {
-      point = ParseUtils.parseLatitudeLongitude(options.pointStr);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
+    Point point = SpatialUtils.parsePointSolrException(options.pointStr, SpatialContext.GEO);
 
     // lat & lon in degrees
-    double latCenter = point[LAT];
-    double lonCenter = point[LON];
+    double latCenter = point.getY();
+    double lonCenter = point.getX();
     
     double distDeg = DistanceUtils.dist2Degrees(options.distance, options.radius);
     Rectangle bbox = DistanceUtils.calcBoxByDistFromPtDEG(latCenter, lonCenter, distDeg, SpatialContext.GEO, null);
@@ -176,8 +152,8 @@ public class LatLonType extends Abstract
     IndexSchema schema = parser.getReq().getSchema();
     
     // Now that we've figured out the ranges, build them!
-    SchemaField latField = subField(options.field, LAT, schema);
-    SchemaField lonField = subField(options.field, LON, schema);
+    SchemaField latSF = subField(options.field, LAT, schema);
+    SchemaField lonSF = subField(options.field, LON, schema);
 
     SpatialDistanceQuery spatial = new SpatialDistanceQuery();
 
@@ -185,14 +161,14 @@ public class LatLonType extends Abstract
     if (options.bbox) {
       BooleanQuery result = new BooleanQuery();
 
-      Query latRange = latField.getType().getRangeQuery(parser, latField,
+      Query latRange = latSF.getType().getRangeQuery(parser, latSF,
                 String.valueOf(latMin),
                 String.valueOf(latMax),
                 true, true);
       result.add(latRange, BooleanClause.Occur.MUST);
 
       if (lonMin != -180 || lonMax != 180) {
-        Query lonRange = lonField.getType().getRangeQuery(parser, lonField,
+        Query lonRange = lonSF.getType().getRangeQuery(parser, lonSF,
                 String.valueOf(lonMin),
                 String.valueOf(lonMax),
                 true, true);
@@ -201,7 +177,7 @@ public class LatLonType extends Abstract
           BooleanQuery bothLons = new BooleanQuery();
           bothLons.add(lonRange, BooleanClause.Occur.SHOULD);
 
-          lonRange = lonField.getType().getRangeQuery(parser, lonField,
+          lonRange = lonSF.getType().getRangeQuery(parser, lonSF,
                 String.valueOf(lon2Min),
                 String.valueOf(lon2Max),
                 true, true);
@@ -218,8 +194,8 @@ public class LatLonType extends Abstract
 
 
     spatial.origField = options.field.getName();
-    spatial.latSource = latField.getType().getValueSource(latField, parser);
-    spatial.lonSource = lonField.getType().getValueSource(lonField, parser);
+    spatial.latSource = latSF.getType().getValueSource(latSF, parser);
+    spatial.lonSource = lonSF.getType().getValueSource(lonSF, parser);
     spatial.latMin = latMin;
     spatial.latMax = latMax;
     spatial.lonMin = lonMin;

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/PointType.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/PointType.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/PointType.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/PointType.java Fri Jan 24 20:16:49 2014
@@ -25,9 +25,6 @@ import org.apache.lucene.search.BooleanC
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.SortField;
-import com.spatial4j.core.io.ParseUtils;
-import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.exception.InvalidShapeException;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.common.params.SolrParams;
@@ -51,7 +48,7 @@ public class PointType extends Coordinat
     SolrParams p = new MapSolrParams(args);
     dimension = p.getInt(DIMENSION, DEFAULT_DIMENSION);
     if (dimension < 1) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
               "The dimension must be > 0: " + dimension);
     }
     args.remove(DIMENSION);
@@ -70,12 +67,7 @@ public class PointType extends Coordinat
   @Override
   public List<IndexableField> createFields(SchemaField field, Object value, float boost) {
     String externalVal = value.toString();
-    String[] point = new String[0];
-    try {
-      point = ParseUtils.parsePoint(null, externalVal, dimension);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
+    String[] point = parseCommaSeparatedList(externalVal, dimension);
 
     // TODO: this doesn't currently support polyFields as sub-field types
     List<IndexableField> f = new ArrayList<IndexableField>(dimension+1);
@@ -135,14 +127,9 @@ public class PointType extends Coordinat
   public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
     //Query could look like: [x1,y1 TO x2,y2] for 2 dimension, but could look like: [x1,y1,z1 TO x2,y2,z2], and can be extrapolated to n-dimensions
     //thus, this query essentially creates a box, cube, etc.
-    String[] p1;
-    String[] p2;
-    try {
-      p1 = ParseUtils.parsePoint(null, part1, dimension);
-      p2 = ParseUtils.parsePoint(null, part2, dimension);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
+    String[] p1 = parseCommaSeparatedList(part1, dimension);
+    String[] p2 = parseCommaSeparatedList(part2, dimension);
+
     BooleanQuery result = new BooleanQuery(true);
     for (int i = 0; i < dimension; i++) {
       SchemaField subSF = subField(field, i, schema);
@@ -154,12 +141,7 @@ public class PointType extends Coordinat
 
   @Override
   public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {
-    String[] p1 = new String[0];
-    try {
-      p1 = ParseUtils.parsePoint(null, externalVal, dimension);
-    } catch (InvalidShapeException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
+    String[] p1 = parseCommaSeparatedList(externalVal, dimension);
     //TODO: should we assert that p1.length == dimension?
     BooleanQuery bq = new BooleanQuery(true);
     for (int i = 0; i < dimension; i++) {
@@ -171,18 +153,22 @@ public class PointType extends Coordinat
   }
 
   /**
-   * Calculates the range and creates a RangeQuery (bounding box) wrapped in a BooleanQuery (unless the dimension is 1, one range for every dimension, AND'd together by a Boolean
-   * @param parser The parser
+   * Calculates the range and creates a RangeQuery (bounding box) wrapped in a BooleanQuery (unless the dimension is
+   * 1, one range for every dimension, AND'd together by a Boolean
+   *
+   * @param parser  The parser
    * @param options The {@link org.apache.solr.search.SpatialOptions} for this filter.
    * @return The Query representing the bounding box around the point.
    */
   @Override
   public Query createSpatialQuery(QParser parser, SpatialOptions options) {
-    Query result = null;
-    double [] point = new double[0];
+    String[] pointStrs = parseCommaSeparatedList(options.pointStr, dimension);
+    double[] point = new double[dimension];
     try {
-      point = ParseUtils.parsePointDouble(null, options.pointStr, dimension);
-    } catch (InvalidShapeException e) {
+      for (int i = 0; i < pointStrs.length; i++) {
+        point[i] = Double.parseDouble(pointStrs[i]);
+      }
+    } catch (NumberFormatException e) {
       throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
     }
     IndexSchema schema = parser.getReq().getSchema();
@@ -192,22 +178,95 @@ public class PointType extends Coordinat
       String upper = String.valueOf(point[0] + options.distance);
       SchemaField subSF = subField(options.field, 0, schema);
       // points must currently be ordered... should we support specifying any two opposite corner points?
-      result = subSF.getType().getRangeQuery(parser, subSF, lower, upper, true, true);
+      return subSF.getType().getRangeQuery(parser, subSF, lower, upper, true, true);
     } else {
       BooleanQuery tmp = new BooleanQuery();
       //TODO: Handle distance measures, as this assumes Euclidean
-      double [] ur = DistanceUtils.vectorBoxCorner(point, null, options.distance, true);
-      double [] ll = DistanceUtils.vectorBoxCorner(point, null, options.distance, false);
+      double[] ur = vectorBoxCorner(point, null, options.distance, true);
+      double[] ll = vectorBoxCorner(point, null, options.distance, false);
       for (int i = 0; i < ur.length; i++) {
         SchemaField subSF = subField(options.field, i, schema);
         Query range = subSF.getType().getRangeQuery(parser, subSF, String.valueOf(ll[i]), String.valueOf(ur[i]), true, true);
         tmp.add(range, BooleanClause.Occur.MUST);
-
       }
-      result = tmp;
+      return tmp;
+    }
+  }
+
+  private static final double SIN_PI_DIV_4 = Math.sin(Math.PI / 4);
+
+  /**
+   * Return the coordinates of a vector that is the corner of a box (upper right or lower left), assuming a Rectangular
+   * coordinate system.  Note, this does not apply for points on a sphere or ellipse (although it could be used as an
+   * approximation).
+   *
+   * @param center     The center point
+   * @param result     Holds the result, potentially resizing if needed.
+   * @param distance   The d from the center to the corner
+   * @param upperRight If true, return the coords for the upper right corner, else return the lower left.
+   * @return The point, either the upperLeft or the lower right
+   */
+  public static double[] vectorBoxCorner(double[] center, double[] result, double distance, boolean upperRight) {
+    if (result == null || result.length != center.length) {
+      result = new double[center.length];
+    }
+    if (upperRight == false) {
+      distance = -distance;
+    }
+    //We don't care about the power here,
+    // b/c we are always in a rectangular coordinate system, so any norm can be used by
+    //using the definition of sine
+    distance = SIN_PI_DIV_4 * distance; // sin(Pi/4) == (2^0.5)/2 == opp/hyp == opp/distance, solve for opp, similarly for cosine
+    for (int i = 0; i < center.length; i++) {
+      result[i] = center[i] + distance;
     }
     return result;
   }
+
+  /**
+   * Given a string containing <i>dimension</i> values encoded in it, separated by commas,
+   * return a String array of length <i>dimension</i> containing the values.
+   *
+   * @param externalVal The value to parse
+   * @param dimension   The expected number of values for the point
+   * @return An array of the values that make up the point (aka vector)
+   * @throws SolrException if the dimension specified does not match the number found
+   */
+  public static String[] parseCommaSeparatedList(String externalVal, int dimension) throws SolrException {
+    //TODO: Should we support sparse vectors?
+    String[] out = new String[dimension];
+    int idx = externalVal.indexOf(',');
+    int end = idx;
+    int start = 0;
+    int i = 0;
+    if (idx == -1 && dimension == 1 && externalVal.length() > 0) {//we have a single point, dimension better be 1
+      out[0] = externalVal.trim();
+      i = 1;
+    } else if (idx > 0) {//if it is zero, that is an error
+      //Parse out a comma separated list of values, as in: 73.5,89.2,7773.4
+      for (; i < dimension; i++) {
+        while (start < end && externalVal.charAt(start) == ' ') start++;
+        while (end > start && externalVal.charAt(end - 1) == ' ') end--;
+        if (start == end) {
+          break;
+        }
+        out[i] = externalVal.substring(start, end);
+        start = idx + 1;
+        end = externalVal.indexOf(',', start);
+        idx = end;
+        if (end == -1) {
+          end = externalVal.length();
+        }
+      }
+    }
+    if (i != dimension) {
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+          "incompatible dimension (" + dimension +
+              ") and values (" + externalVal + ").  Only " + i + " values specified");
+    }
+    return out;
+  }
+
 }
 
 

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java Fri Jan 24 20:16:49 2014
@@ -17,9 +17,8 @@ package org.apache.solr.search.function.
  * limitations under the License.
  */
 
+import com.spatial4j.core.context.SpatialContext;
 import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.exception.InvalidShapeException;
-import com.spatial4j.core.io.ParseUtils;
 import com.spatial4j.core.shape.Point;
 import org.apache.lucene.queries.function.ValueSource;
 import org.apache.lucene.queries.function.valuesource.ConstNumberSource;
@@ -34,6 +33,7 @@ import org.apache.solr.schema.SchemaFiel
 import org.apache.solr.search.FunctionQParser;
 import org.apache.solr.search.SyntaxError;
 import org.apache.solr.search.ValueSourceParser;
+import org.apache.solr.util.SpatialUtils;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -134,9 +134,7 @@ public class GeoDistValueSourceParser ex
       // note: uses Haversine by default but can be changed via distCalc=...
       SpatialStrategy strategy = ((SpatialStrategyMultiValueSource) mv2).strategy;
       Point queryPoint = strategy.getSpatialContext().makePoint(constants[1], constants[0]);
-      //TODO Spatial4j 0.4 will have a direct constant
-      double multiplier = DistanceUtils.degrees2Dist(1, DistanceUtils.EARTH_MEAN_RADIUS_KM);
-      return strategy.makeDistanceValueSource(queryPoint, multiplier);
+      return strategy.makeDistanceValueSource(queryPoint, DistanceUtils.DEG_TO_KM);
     }
 
     if (constants != null && other instanceof VectorValueSource) {
@@ -158,15 +156,12 @@ public class GeoDistValueSourceParser ex
   }
 
   private MultiValueSource parsePoint(FunctionQParser fp) throws SyntaxError {
-    String pt = fp.getParam(SpatialParams.POINT);
-    if (pt == null) return null;
-    double[] point = null;
-    try {
-      point = ParseUtils.parseLatitudeLongitude(pt);
-    } catch (InvalidShapeException e) {
-      throw new SyntaxError("Bad spatial pt:" + pt);
-    }
-    return new VectorValueSource(Arrays.<ValueSource>asList(new DoubleConstValueSource(point[0]), new DoubleConstValueSource(point[1])));
+    String ptStr = fp.getParam(SpatialParams.POINT);
+    if (ptStr == null) return null;
+    Point point = SpatialUtils.parsePointSolrException(ptStr, SpatialContext.GEO);
+    //assume Lat Lon order
+    return new VectorValueSource(
+        Arrays.<ValueSource>asList(new DoubleConstValueSource(point.getY()), new DoubleConstValueSource(point.getX())));
   }
 
   private double[] getConstants(MultiValueSource vs) {

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java Fri Jan 24 20:16:49 2014
@@ -18,7 +18,6 @@ package org.apache.solr.search.function.
 
 import org.apache.lucene.queries.function.FunctionValues;
 import org.apache.lucene.queries.function.valuesource.MultiValueSource;
-import com.spatial4j.core.distance.DistanceUtils;
 
 /**
  * While not strictly a distance, the Sq. Euclidean Distance is often all that is needed in many applications
@@ -49,7 +48,7 @@ public class SquaredEuclideanFunction ex
     dv1.doubleVal(doc, vals1);
     dv2.doubleVal(doc, vals2);
 
-    return DistanceUtils.distSquaredCartesian(vals1, vals2);
+    return distSquaredCartesian(vals1, vals2);
   }
 
   @Override

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java Fri Jan 24 20:16:49 2014
@@ -22,7 +22,6 @@ import org.apache.lucene.queries.functio
 import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
 import org.apache.lucene.queries.function.valuesource.MultiValueSource;
 import org.apache.lucene.search.IndexSearcher;
-import com.spatial4j.core.distance.DistanceUtils;
 import org.apache.solr.common.SolrException;
 
 import java.io.IOException;
@@ -75,7 +74,79 @@ public class VectorDistanceFunction exte
     double[] vals2 = new double[source1.dimension()];
     dv1.doubleVal(doc, vals1);
     dv2.doubleVal(doc, vals2);
-    return DistanceUtils.vectorDistance(vals1, vals2, power, oneOverPower);
+    return vectorDistance(vals1, vals2, power, oneOverPower);
+  }
+
+  /**
+   * Calculate the p-norm (i.e. length) between two vectors.
+   * <p/>
+   * See <a href="http://en.wikipedia.org/wiki/Lp_space">Lp space</a>
+   *
+   * @param vec1  The first vector
+   * @param vec2  The second vector
+   * @param power The power (2 for cartesian distance, 1 for manhattan, etc.)
+   * @return The length.
+   *
+   * @see #vectorDistance(double[], double[], double, double)
+   *
+   */
+  public static double vectorDistance(double[] vec1, double[] vec2, double power) {
+    //only calc oneOverPower if it's needed
+    double oneOverPower = (power == 0 || power == 1.0 || power == 2.0) ? Double.NaN : 1.0 / power;
+    return vectorDistance(vec1, vec2, power, oneOverPower);
+  }
+
+  /**
+   * Calculate the p-norm (i.e. length) between two vectors.
+   *
+   * @param vec1         The first vector
+   * @param vec2         The second vector
+   * @param power        The power (2 for cartesian distance, 1 for manhattan, etc.)
+   * @param oneOverPower If you've pre-calculated oneOverPower and cached it, use this method to save
+   *                     one division operation over {@link #vectorDistance(double[], double[], double)}.
+   * @return The length.
+   */
+  public static double vectorDistance(double[] vec1, double[] vec2, double power, double oneOverPower) {
+    double result = 0;
+
+    if (power == 0) {
+      for (int i = 0; i < vec1.length; i++) {
+        result += vec1[i] - vec2[i] == 0 ? 0 : 1;
+      }
+    } else if (power == 1.0) { // Manhattan
+      for (int i = 0; i < vec1.length; i++) {
+        result += Math.abs(vec1[i] - vec2[i]);
+      }
+    } else if (power == 2.0) { // Cartesian
+      result = Math.sqrt(distSquaredCartesian(vec1, vec2));
+    } else if (power == Integer.MAX_VALUE || Double.isInfinite(power)) {//infinite norm?
+      for (int i = 0; i < vec1.length; i++) {
+        result = Math.max(result, Math.max(vec1[i], vec2[i]));
+      }
+    } else {
+      for (int i = 0; i < vec1.length; i++) {
+        result += Math.pow(vec1[i] - vec2[i], power);
+      }
+      result = Math.pow(result, oneOverPower);
+    }
+    return result;
+  }
+
+  /**
+   * The square of the cartesian Distance.  Not really a distance, but useful if all that matters is
+   * comparing the result to another one.
+   *
+   * @param vec1 The first point
+   * @param vec2 The second point
+   * @return The squared cartesian distance
+   */
+  public static double distSquaredCartesian(double[] vec1, double[] vec2) {
+    double result = 0;
+    for (int i = 0; i < vec1.length; i++) {
+      double v = vec1[i] - vec2[i];
+      result += v * v;
+    }
+    return result;
   }
 
   @Override

Modified: lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/collection1/conf/schema-spatial.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/collection1/conf/schema-spatial.xml?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/collection1/conf/schema-spatial.xml (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/collection1/conf/schema-spatial.xml Fri Jan 24 20:16:49 2014
@@ -39,11 +39,13 @@
               prefixTree="geohash" units="degrees" />
 
     <fieldType name="stqpt_u"  class="solr.SpatialTermQueryPrefixTreeFieldType"
-        geo="false" distCalculator="cartesian^2" worldBounds="0 0 1000 1000" units="degrees"/>
+        geo="false" distCalculator="cartesian^2" worldBounds="ENVELOPE(0, 1000, 1000, 0)" units="degrees"/>
 
     <fieldType name="pointvector" class="solr.SpatialPointVectorFieldType"
                numberType="tdouble" units="degrees"/>
 
+    <fieldType name="stqpt_u_oldworldbounds"  class="solr.SpatialTermQueryPrefixTreeFieldType"
+               geo="false" distCalculator="cartesian^2" worldBounds="0 0 1000 1000" units="degrees"/>
   </types>
 
 

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java Fri Jan 24 20:16:49 2014
@@ -21,12 +21,22 @@ import com.carrotsearch.randomizedtestin
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 import com.spatial4j.core.context.SpatialContext;
 import com.spatial4j.core.distance.DistanceUtils;
+import com.spatial4j.core.shape.Point;
+import com.spatial4j.core.shape.Rectangle;
+import com.spatial4j.core.shape.impl.RectangleImpl;
+import org.apache.lucene.spatial.SpatialStrategy;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.schema.AbstractSpatialFieldType;
+import org.apache.solr.schema.FieldType;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.util.SpatialUtils;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.text.ParseException;
 import java.util.Arrays;
 
 /**
@@ -151,20 +161,20 @@ public class TestSolr4Spatial extends So
 
     assertQ(req(
         "fl", "id," + fieldName, "q", "*:*", "rows", "1000",
-        "fq", "{!field f="+fieldName+"}Intersects(Circle(89.9,-130 d=9))"),
+        "fq", "{!geofilt sfield="+fieldName+" pt="+IN+" d=9}"),
         "//result/doc/*[@name='" + fieldName + "']//text()='" + OUT + "'");
   }
 
   @Test
-  public void checkQueryEmptyIndex() {
+  public void checkQueryEmptyIndex() throws ParseException {
     checkHits(fieldName, "0,0", 100, 0);//doesn't error
   }
 
-  private void checkHits(String fieldName, String pt, double distKM, int count, int ... docIds) {
+  private void checkHits(String fieldName, String pt, double distKM, int count, int ... docIds) throws ParseException {
     checkHits(fieldName, true, pt, distKM, count, docIds);
   }
 
-  private void checkHits(String fieldName, boolean exact, String ptStr, double distKM, int count, int ... docIds) {
+  private void checkHits(String fieldName, boolean exact, String ptStr, double distKM, int count, int ... docIds) throws ParseException {
     String [] tests = new String[docIds != null && docIds.length > 0 ? docIds.length + 1 : 1];
     //test for presence of required ids first
     int i = 0;
@@ -177,20 +187,23 @@ public class TestSolr4Spatial extends So
     // that there may be a more specific detailed id to investigate.
     tests[i++] = "*[count(//doc)=" + count + "]";
 
-    //Test using the Solr 4 syntax
+    //Test using the Lucene spatial syntax
     {
       //never actually need the score but lets test
       String score = new String[]{null, "none","distance","recipDistance"}[random().nextInt(4)];
 
       double distDEG = DistanceUtils.dist2Degrees(distKM, DistanceUtils.EARTH_MEAN_RADIUS_KM);
-      String circleStr = "Circle(" + ptStr.replaceAll(" ", "") + " d=" + distDEG + ")";
+      Point point = SpatialUtils.parsePoint(ptStr, SpatialContext.GEO);
+      String circleStr = "BUFFER(POINT(" + point.getX()+" "+point.getY()+")," + distDEG + ")";
       String shapeStr;
       if (exact) {
         shapeStr = circleStr;
       } else {//bbox
         //the GEO is an assumption
         SpatialContext ctx = SpatialContext.GEO;
-        shapeStr = ctx.toString( ctx.readShape(circleStr).getBoundingBox() );
+        Rectangle bbox = ctx.readShapeFromWkt(circleStr).getBoundingBox();
+        shapeStr = "ENVELOPE(" + bbox.getMinX() + ", " + bbox.getMaxX() +
+            ", " + bbox.getMaxY() + ", " + bbox.getMinY() + ")";
       }
 
       //FYI default distErrPct=0.025 works with the tests in this file
@@ -200,7 +213,7 @@ public class TestSolr4Spatial extends So
               + "}Intersects(" + shapeStr + ")"),
           tests);
     }
-    //Test using the Solr 3 syntax
+    //Test using geofilt
     {
       assertQ(req(
           "fl", "id", "q", "*:*", "rows", "1000",
@@ -219,8 +232,8 @@ public class TestSolr4Spatial extends So
 
     String score = random().nextBoolean() ? "none" : "distance";//never actually need the score but lets test
     assertQ(req(
-        "fl", "id", "q","*:*", "rows", "1000",
-        "fq", "{! score="+score+" df="+fieldName+"}[32,-80 TO 33,-79]"),//lower-left to upper-right
+        "fl", "id", "q","*:*", "rows", "1000",    // testing quotes in range too
+        "fq", "{! score="+score+" df="+fieldName+"}[32,-80 TO \"33 , -79\"]"),//lower-left to upper-right
 
         "//result/doc/*[@name='id'][.='" + docId + "']",
         "*[count(//doc)=" + count + "]");
@@ -234,8 +247,9 @@ public class TestSolr4Spatial extends So
     assertU(commit());
 
     //test absence of score=distance means it doesn't score
+
     assertJQ(req(
-        "q", fieldName +":\"Intersects(Circle(3,4 d=9))\"",
+        "q", radiusQuery(3, 4, 9, null, null),
         "fl","id,score")
         , 1e-9
         , "/response/docs/[0]/score==1.0"
@@ -244,7 +258,7 @@ public class TestSolr4Spatial extends So
 
     //score by distance
     assertJQ(req(
-        "q", "{! score=distance}"+fieldName +":\"Intersects(Circle(3,4 d=9))\"",
+        "q", radiusQuery(3, 4, 9, "distance", null),
         "fl","id,score",
         "sort","score asc")//want ascending due to increasing distance
         , 1e-3
@@ -255,7 +269,7 @@ public class TestSolr4Spatial extends So
     );
     //score by recipDistance
     assertJQ(req(
-        "q", "{! score=recipDistance}"+fieldName +":\"Intersects(Circle(3,4 d=9))\"",
+        "q", radiusQuery(3, 4, 9, "recipDistance", null),
         "fl","id,score",
         "sort","score desc")//want descending
         , 1e-3
@@ -268,7 +282,7 @@ public class TestSolr4Spatial extends So
     //score by distance and don't filter
     assertJQ(req(
         //circle radius is small and shouldn't match either, but we disable filtering
-        "q", "{! score=distance filter=false}"+fieldName +":\"Intersects(Circle(3,4 d=0.000001))\"",
+        "q", radiusQuery(3, 4, 0.000001, "distance", "false"),
         "fl","id,score",
         "sort","score asc")//want ascending due to increasing distance
         , 1e-3
@@ -280,7 +294,7 @@ public class TestSolr4Spatial extends So
 
     //query again with the query point closer to #101, and check the new ordering
     assertJQ(req(
-        "q", "{! score=distance}"+fieldName +":\"Intersects(Circle(4,0 d=9))\"",
+        "q", radiusQuery(4, 0, 9, "distance", null),
         "fl","id,score",
         "sort","score asc")//want ascending due to increasing distance
         , 1e-4
@@ -293,7 +307,7 @@ public class TestSolr4Spatial extends So
         "q","-id:999",//exclude that doc
         "fl","id,score",
         "sort","query($sortQuery) asc", //want ascending due to increasing distance
-        "sortQuery", "{! score=distance}"+fieldName +":\"Intersects(Circle(3,4 d=9))\"" )
+        "sortQuery", radiusQuery(3, 4, 9, "distance", null))
         , 1e-4
         , "/response/docs/[0]/id=='100'"
         , "/response/docs/[1]/id=='101'"  );
@@ -303,12 +317,28 @@ public class TestSolr4Spatial extends So
         "q","-id:999",//exclude that doc
         "fl","id,score",
         "sort","query($sortQuery) asc", //want ascending due to increasing distance
-        "sortQuery", "{! score=distance}"+fieldName +":\"Intersects(Circle(4,0 d=9))\"" )
+        "sortQuery", radiusQuery(4, 0, 9, "distance", null))
         , 1e-4
         , "/response/docs/[0]/id=='101'"
         , "/response/docs/[1]/id=='100'"  );
   }
 
+  private String radiusQuery(double lat, double lon, double dDEG, String score, String filter) {
+    //Choose between the Solr/Geofilt syntax, and the Lucene spatial module syntax
+    if (random().nextBoolean()) {
+      return "{!geofilt " +
+          "sfield=" + fieldName + " "
+          + (score != null ? "score="+score : "") + " "
+          + (filter != null ? "filter="+filter : "") + " "
+          + "pt=" + lat + "," + lon + " d=" + (dDEG * DistanceUtils.DEG_TO_KM) + "}";
+    } else {
+      return "{! "
+          + (score != null ? "score="+score : "") + " "
+          + (filter != null ? "filter="+filter : "") + " "
+          + "}" + fieldName + ":\"Intersects(BUFFER(POINT(" + lon + " " + lat + ")," + dDEG + "))\"";
+    }
+  }
+
   @Test
   public void testSortMultiVal() throws Exception {
     RandomizedTest.assumeFalse("Multivalue not supported for this field", fieldName.equals("pointvector"));
@@ -318,7 +348,7 @@ public class TestSolr4Spatial extends So
     assertU(commit());
 
     assertJQ(req(
-        "q", "{! score=distance}"+fieldName +":\"Intersects(Circle(3,4 d=9))\"",
+        "q", radiusQuery(3, 4, 9, "distance", null),
         "fl","id,score",
         "sort","score asc")//want ascending due to increasing distance
         , 1e-4
@@ -327,4 +357,31 @@ public class TestSolr4Spatial extends So
     );
   }
 
+  @Test
+  public void solr4OldShapeSyntax() throws Exception {
+    assumeFalse("Mostly just valid for prefix-tree", fieldName.equals("pointvector"));
+
+    //we also test that the old syntax is parsed in worldBounds in the schema
+    {
+      IndexSchema schema = h.getCore().getLatestSchema();
+      AbstractSpatialFieldType type = (AbstractSpatialFieldType) schema.getFieldTypeByName("stqpt_u_oldworldbounds");
+      SpatialContext ctx = type.getStrategy("foo").getSpatialContext();
+      assertEquals(new RectangleImpl(0, 1000, 0, 1000, ctx), ctx.getWorldBounds());
+    }
+
+    //syntax supported in Solr 4 but not beyond
+    //   See Spatial4j LegacyShapeReadWriterFormat
+    String rect = "-74.093 41.042 -69.347 44.558";//minX minY maxX maxY
+    String circ = "Circle(4.56,1.23 d=0.0710)";
+
+    //show we can index this (without an error)
+    assertU(adoc("id", "rect", fieldName, rect));
+    assertU(adoc("id", "circ", fieldName, circ));
+    assertU(commit());
+
+    //only testing no error
+    assertJQ(req("q", "{!field f=" + fieldName + "}Intersects(" + rect + ")"));
+    assertJQ(req("q", "{!field f=" + fieldName + "}Intersects(" + circ + ")"));
+  }
+
 }

Modified: lucene/dev/branches/branch_4x/solr/licenses/spatial4j-NOTICE.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/licenses/spatial4j-NOTICE.txt?rev=1561142&r1=1561141&r2=1561142&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/licenses/spatial4j-NOTICE.txt (original)
+++ lucene/dev/branches/branch_4x/solr/licenses/spatial4j-NOTICE.txt Fri Jan 24 20:16:49 2014
@@ -1,5 +1,5 @@
-Apache Commons Lang
-Copyright 2001-2008 The Apache Software Foundation
+Spatial4j
+Copyright 2012-2014 The Apache Software Foundation
 
 This product includes software developed by
 The Apache Software Foundation (http://www.apache.org/).