pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / spatial / src / java / org / apache / lucene / spatial / tier / LatLongDistanceFilter.java
1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package org.apache.lucene.spatial.tier;
19
20 import java.io.IOException;
21 import org.apache.lucene.index.IndexReader;
22 import org.apache.lucene.search.FilteredDocIdSet;
23 import org.apache.lucene.search.FieldCache;
24 import org.apache.lucene.search.Filter;
25 import org.apache.lucene.search.DocIdSet;
26 import org.apache.lucene.spatial.DistanceUtils;
27
28
29 /**
30  * <p><font color="red"><b>NOTE:</b> This API is still in
31  * flux and might change in incompatible ways in the next
32  * release.</font>
33  */
34 public class LatLongDistanceFilter extends DistanceFilter {
35
36   /**
37    * 
38    */
39   private static final long serialVersionUID = 1L;
40   
41   double lat;
42   double lng;
43   String latField;
44   String lngField;
45
46   int nextOffset = 0;
47   
48   /**
49    * Provide a distance filter based from a center point with a radius
50    * in miles.
51    * @param startingFilter Filter to start from
52    * @param lat
53    * @param lng
54    * @param miles
55    * @param latField
56    * @param lngField
57    */
58   public LatLongDistanceFilter(Filter startingFilter, double lat, double lng, double miles, String latField, String lngField) {
59     super(startingFilter, miles);
60     this.lat = lat;
61     this.lng = lng;
62     this.latField = latField;
63     this.lngField = lngField;
64   }
65   
66   @Override
67   public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
68
69     final double[] latIndex = FieldCache.DEFAULT.getDoubles(reader, latField);
70     final double[] lngIndex = FieldCache.DEFAULT.getDoubles(reader, lngField);
71
72     final int docBase = nextDocBase;
73     nextDocBase += reader.maxDoc();
74
75     return new FilteredDocIdSet(startingFilter.getDocIdSet(reader)) {
76       @Override
77       protected boolean match(int doc) {
78         double x = latIndex[doc];
79         double y = lngIndex[doc];
80       
81         // round off lat / longs if necessary
82         //      x = DistanceHandler.getPrecision(x, precise);
83         //      y = DistanceHandler.getPrecision(y, precise);
84       
85         String ck = Double.toString(x)+","+Double.toString(y);
86         Double cachedDistance = distanceLookupCache.get(ck);
87
88         double d;
89         if (cachedDistance != null){
90           d = cachedDistance.doubleValue();
91         } else {
92           d = DistanceUtils.getDistanceMi(lat, lng, x, y);
93           distanceLookupCache.put(ck, d);
94         }
95
96         if (d < distance) {
97           // Save distances, so they can be pulled for
98           // sorting after filtering is done:
99           distances.put(doc+docBase, d);
100           return true;
101         } else {
102           return false;
103         }
104       }
105     };
106   }
107
108   /** Returns true if <code>o</code> is equal to this. */
109   @Override
110   public boolean equals(Object o) {
111     if (this == o) return true;
112     if (!(o instanceof LatLongDistanceFilter)) return false;
113     LatLongDistanceFilter other = (LatLongDistanceFilter) o;
114
115     if (!this.startingFilter.equals(other.startingFilter) ||
116         this.distance != other.distance ||
117         this.lat != other.lat ||
118         this.lng != other.lng ||
119         !this.latField.equals(other.latField) ||
120         !this.lngField.equals(other.lngField)) {
121       return false;
122     }
123     return true;
124   }
125
126   /** Returns a hash code value for this object.*/
127   @Override
128   public int hashCode() {
129     int h = Double.valueOf(distance).hashCode();
130     h ^= startingFilter.hashCode();
131     h ^= Double.valueOf(lat).hashCode();
132     h ^= Double.valueOf(lng).hashCode();
133     h ^= latField.hashCode();
134     h ^= lngField.hashCode();
135     return h;
136   }
137 }