/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.lucene.spatial.tier.projections; /** * <p><font color="red"><b>NOTE:</b> This API is still in * flux and might change in incompatible ways in the next * release.</font> */ public class CartesianTierPlotter { public static final String DEFALT_FIELD_PREFIX = "_tier_"; private static final double LOG_2 = Math.log(2); final int tierLevel; int tierLength; int tierBoxes; int tierVerticalPosDivider; final IProjector projector; final String fieldPrefix; Double idd = Double.valueOf(180); public CartesianTierPlotter (int tierLevel, IProjector projector, String fieldPrefix) { this.tierLevel = tierLevel; this.projector = projector; this.fieldPrefix = fieldPrefix; setTierLength(); setTierBoxes(); setTierVerticalPosDivider(); } private void setTierLength (){ this.tierLength = (int) Math.pow(2 , this.tierLevel); } private void setTierBoxes () { this.tierBoxes = (int)Math.pow(this.tierLength, 2); } /** * Get nearest max power of 10 greater than * the tierlen * e.g * tierId of 13 has tierLen 8192 * nearest max power of 10 greater than tierLen * would be 10,000 */ private void setTierVerticalPosDivider() { // ceiling of log base 10 of tierLen tierVerticalPosDivider = Double.valueOf(Math.ceil( Math.log10(Integer.valueOf(this.tierLength).doubleValue()))).intValue(); // tierVerticalPosDivider = (int)Math.pow(10, tierVerticalPosDivider ); } public double getTierVerticalPosDivider(){ return tierVerticalPosDivider; } /** * TierBoxId is latitude box id + longitude box id * where latitude box id, and longitude box id are transposed in to position * coordinates. * * @param latitude * @param longitude */ public double getTierBoxId (double latitude, double longitude) { double[] coords = projector.coords(latitude, longitude); double id = getBoxId(coords[0]) + (getBoxId(coords[1]) / tierVerticalPosDivider); return id ; } private double getBoxId (double coord){ return Math.floor(coord / (idd / this.tierLength)); } @SuppressWarnings("unused") private double getBoxId (double coord, int tierLen){ return Math.floor(coord / (idd / tierLen) ); } /** * get the string name representing current tier * _localTier<tiedId> */ public String getTierFieldName (){ return fieldPrefix + this.tierLevel; } /** * get the string name representing tierId * _localTier<tierId> * @param tierId */ public String getTierFieldName (int tierId){ return fieldPrefix + tierId; } /** * Find the tier with the best fit for a bounding box * Best fit is defined as the ceiling of * log2 (circumference of earth / distance) * distance is defined as the smallest box fitting * the corner between a radius and a bounding box. * * Distances less than a mile return 15, finer granularity is * in accurate */ public int bestFit(double miles){ //28,892 a rough circumference of the earth int circ = 28892; double r = miles / 2.0; double corner = r - Math.sqrt(Math.pow(r, 2) / 2.0d); double times = circ / corner; int bestFit = (int)Math.ceil(log2(times)) + 1; if (bestFit > 15) { // 15 is the granularity of about 1 mile // finer granularity isn't accurate with standard java math return 15; } return bestFit; } /** * a log to the base 2 formula * <code>Math.log(value) / Math.log(2)</code> * @param value */ public static double log2(double value) { return Math.log(value) / LOG_2; } /** * Returns the ID of the tier level plotting is occuring at * * @return ID of the tier level plotting is occuring at */ public int getTierLevelId() { return this.tierLevel; } }