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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org.apache.lucene.spatial.tier.projections;
21 * <p><font color="red"><b>NOTE:</b> This API is still in
22 * flux and might change in incompatible ways in the next
25 public class CartesianTierPlotter {
26 public static final String DEFALT_FIELD_PREFIX = "_tier_";
31 int tierVerticalPosDivider;
32 final IProjector projector;
33 final String fieldPrefix;
34 Double idd = Double.valueOf(180);
36 public CartesianTierPlotter (int tierLevel, IProjector projector, String fieldPrefix) {
38 this.tierLevel = tierLevel;
39 this.projector = projector;
40 this.fieldPrefix = fieldPrefix;
44 setTierVerticalPosDivider();
47 private void setTierLength (){
48 this.tierLength = (int) Math.pow(2 , this.tierLevel);
51 private void setTierBoxes () {
52 this.tierBoxes = (int)Math.pow(this.tierLength, 2);
56 * Get nearest max power of 10 greater than
59 * tierId of 13 has tierLen 8192
60 * nearest max power of 10 greater than tierLen
64 private void setTierVerticalPosDivider() {
66 // ceiling of log base 10 of tierLen
68 tierVerticalPosDivider = Double.valueOf(Math.ceil(
69 Math.log10(Integer.valueOf(this.tierLength).doubleValue()))).intValue();
72 tierVerticalPosDivider = (int)Math.pow(10, tierVerticalPosDivider );
76 public double getTierVerticalPosDivider(){
77 return tierVerticalPosDivider;
81 * TierBoxId is latitude box id + longitude box id
82 * where latitude box id, and longitude box id are transposed in to position
88 public double getTierBoxId (double latitude, double longitude) {
90 double[] coords = projector.coords(latitude, longitude);
92 double id = getBoxId(coords[0]) + (getBoxId(coords[1]) / tierVerticalPosDivider);
97 private double getBoxId (double coord){
100 return Math.floor(coord / (idd / this.tierLength));
103 @SuppressWarnings("unused")
104 private double getBoxId (double coord, int tierLen){
105 return Math.floor(coord / (idd / tierLen) );
108 * get the string name representing current tier
109 * _localTier<tiedId>
111 public String getTierFieldName (){
113 return fieldPrefix + this.tierLevel;
117 * get the string name representing tierId
118 * _localTier<tierId>
121 public String getTierFieldName (int tierId){
123 return fieldPrefix + tierId;
127 * Find the tier with the best fit for a bounding box
128 * Best fit is defined as the ceiling of
129 * log2 (circumference of earth / distance)
130 * distance is defined as the smallest box fitting
131 * the corner between a radius and a bounding box.
133 * Distances less than a mile return 15, finer granularity is
136 public int bestFit(double miles){
138 //28,892 a rough circumference of the earth
141 double r = miles / 2.0;
143 double corner = r - Math.sqrt(Math.pow(r, 2) / 2.0d);
144 double times = circ / corner;
145 int bestFit = (int)Math.ceil(log2(times)) + 1;
148 // 15 is the granularity of about 1 mile
149 // finer granularity isn't accurate with standard java math
156 * a log to the base 2 formula
157 * <code>Math.log(value) / Math.log(2)</code>
160 public double log2(double value) {
162 return Math.log(value) / Math.log(2);