alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Lucene example source code file (CartesianPolyFilterBuilder.java)

This example Lucene source code file (CartesianPolyFilterBuilder.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Lucene tags/keywords

cartesianpolyfilterbuilder, cartesianshapefilter, cartesiantierplotter, cartesiantierplotter, filter, floatlatlng, latlng, llrect, math, miles_floor, miles_floor, shape, shape, string, string

The Lucene CartesianPolyFilterBuilder.java source code

/**
 * 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;

import java.math.BigDecimal;
import java.math.RoundingMode;

import org.apache.lucene.search.Filter;
import org.apache.lucene.spatial.tier.projections.CartesianTierPlotter;
import org.apache.lucene.spatial.tier.projections.IProjector;
import org.apache.lucene.spatial.tier.projections.SinusoidalProjector;
import org.apache.lucene.spatial.geometry.LatLng;
import org.apache.lucene.spatial.geometry.FloatLatLng;
import org.apache.lucene.spatial.geometry.shape.LLRect;


/**
 * <p>NOTE: This API is still in
 * flux and might change in incompatible ways in the next
 * release.</font>
 */
public class CartesianPolyFilterBuilder {

  // Finer granularity than 1 mile isn't accurate with
  // standard java math.  Also, there's already a 2nd
  // precise filter, if needed, in DistanceQueryBuilder,
  // that will make the filtering exact.
  public static final double MILES_FLOOR = 1.0;

  private IProjector projector = new SinusoidalProjector();
  private final String tierPrefix;
	private int minTier;
	private int maxTier;
  /**
   * 
   * @param tierPrefix The prefix for the name of the fields containing the tier info
   * @param minTierIndexed The minimum tier level indexed
   * @param maxTierIndexed The maximum tier level indexed
   */
  public CartesianPolyFilterBuilder( String tierPrefix, int minTierIndexed, int maxTierIndexed ) {
    this.tierPrefix = tierPrefix;
	this.minTier = minTierIndexed;
	this.maxTier = maxTierIndexed;
  }
  
  public Shape getBoxShape(double latitude, double longitude, double miles)
  {  
    if (miles < MILES_FLOOR) {
      miles = MILES_FLOOR;
    }
    LLRect box1 = LLRect.createBox( new FloatLatLng( latitude, longitude ), miles, miles );
    LatLng ll = box1.getLowerLeft();
    LatLng ur = box1.getUpperRight();

    double latY = ur.getLat();
    double latX = ll.getLat();
    double longY = ur.getLng();
    double longX = ll.getLng();
    double longX2 = 0.0;
	//These two if checks setup us up to deal with issues around the prime meridian and the 180th meridian
	//In these two cases, we need to get tiles (tiers) from the lower left up to the meridian and then 
	//from the meridan to the upper right
	//Are we crossing the 180 deg. longitude, if so, we need to do some special things
    if (ur.getLng() < 0.0 && ll.getLng() > 0.0) {
	longX2 = ll.getLng();
 	longX = -180.0;	
    }
	//are we crossing the prime meridian (0 degrees)?  If so, we need to account for it and boxes on both sides
    if (ur.getLng() > 0.0 && ll.getLng() < 0.0) {
	longX2 = ll.getLng();
 	longX = 0.0;	
    }
    
    //System.err.println("getBoxShape:"+latY+"," + longY);
    //System.err.println("getBoxShape:"+latX+"," + longX);
    CartesianTierPlotter ctp = new CartesianTierPlotter(2, projector,tierPrefix);
    int bestFit = ctp.bestFit(miles);
	if (bestFit < minTier){
		bestFit = minTier;
	} else if (bestFit > maxTier){
		bestFit = maxTier;
	}
    
    ctp = new CartesianTierPlotter(bestFit, projector,tierPrefix);
    Shape shape = new Shape(ctp.getTierFieldName());
    
    // generate shape
    // iterate from startX->endX
    //     iterate from startY -> endY
    //      shape.add(currentLat.currentLong);
	//for the edge cases (prime meridian and the 180th meridian), this call handles all tiles East of the meridian
    //for all other cases, it handles the whole set of tiles
    shape = getShapeLoop(shape,ctp,latX,longX,latY,longY);
	if (longX2 != 0.0) {
	      if (longX == 0.0) {
	        longX = longX2;
	        longY = 0.0;
	        //handles the lower left longitude to the prime meridian
	        //shape = getShapeLoop(shape, ctp, latX, longX, latY, longY);
	      } else {
	        //this clause handles the lower left longitude up to the 180 meridian
	        longX = longX2;
	        longY = 180.0;
	      }
	      shape = getShapeLoop(shape, ctp, latX, longX, latY, longY);

	      //System.err.println("getBoxShape2:"+latY+"," + longY);
	        //System.err.println("getBoxShape2:"+latX+"," + longX);
	    }
	
 
    return shape; 
  } 
  
  public Shape getShapeLoop(Shape shape, CartesianTierPlotter ctp, double latX, double longX, double latY, double longY)
  {  
 
    //System.err.println("getShapeLoop:"+latY+"," + longY);
    //System.err.println("getShapeLoop:"+latX+"," + longX);
    double beginAt = ctp.getTierBoxId(latX, longX);
    double endAt = ctp.getTierBoxId(latY, longY);
    if (beginAt > endAt){
	      double tmp = beginAt;
	      beginAt = endAt;
	      endAt = tmp;
	}
    double tierVert = ctp.getTierVerticalPosDivider();
    //System.err.println(" | "+ beginAt+" | "+ endAt);
    
    double startX = beginAt - (beginAt %1);
    double startY = beginAt - startX ; //should give a whole number
    
    double endX = endAt - (endAt %1);
    double endY = endAt -endX; //should give a whole number
    
    int scale = (int)Math.log10(tierVert);
    endY = new BigDecimal(endY).setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
    startY = new BigDecimal(startY).setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
    double xInc = 1.0d / tierVert;
    xInc = new BigDecimal(xInc).setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
    
    //System.err.println("go from startX:"+startX+" to:" + endX);
    for (; startX <= endX; startX++){
      
      double itY = startY;
      //System.err.println("go from startY:"+startY+" to:" + endY);
      while (itY <= endY){
        //create a boxId
        // startX.startY
        double boxId = startX + itY ;
        shape.addBox(boxId);
        //System.err.println("----"+startX+" and "+itY);
        //System.err.println("----"+boxId);
        itY += xInc;
        
        // java keeps 0.0001 as 1.0E-1
        // which ends up as 0.00011111
        itY = new BigDecimal(itY).setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
      }
    }
    return shape;
  }
  
  public Filter getBoundingArea(double latitude, double longitude, double miles) 
  {
    Shape shape = getBoxShape(latitude, longitude, miles);
    return new CartesianShapeFilter(shape, shape.getTierId());
  }
}

Other Lucene examples (source code examples)

Here is a short list of links related to this Lucene CartesianPolyFilterBuilder.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.