/*
* Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazonaws.geo.s2.internal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import com.amazonaws.geo.model.GeoPoint;
import com.google.common.geometry.S2Cell;
import com.google.common.geometry.S2CellId;
import com.google.common.geometry.S2CellUnion;
import com.google.common.geometry.S2LatLng;
import com.google.common.geometry.S2LatLngRect;
public class S2Manager {
public static S2CellUnion findCellIds(S2LatLngRect latLngRect) {
ConcurrentLinkedQueue<S2CellId> queue = new ConcurrentLinkedQueue<S2CellId>();
ArrayList<S2CellId> cellIds = new ArrayList<S2CellId>();
for (S2CellId c = S2CellId.begin(0); !c.equals(S2CellId.end(0)); c = c.next()) {
if (containsGeodataToFind(c, latLngRect)) {
queue.add(c);
}
}
processQueue(queue, cellIds, latLngRect);
assert queue.size() == 0;
queue = null;
if (cellIds.size() > 0) {
S2CellUnion cellUnion = new S2CellUnion();
cellUnion.initFromCellIds(cellIds); // This normalize the cells.
// cellUnion.initRawCellIds(cellIds); // This does not normalize the cells.
cellIds = null;
return cellUnion;
}
return null;
}
private static boolean containsGeodataToFind(S2CellId c, S2LatLngRect latLngRect) {
if (latLngRect != null) {
return latLngRect.intersects(new S2Cell(c));
}
return false;
}
private static void processQueue(ConcurrentLinkedQueue<S2CellId> queue, ArrayList<S2CellId> cellIds,
S2LatLngRect latLngRect) {
for (S2CellId c = queue.poll(); c != null; c = queue.poll()) {
if (!c.isValid()) {
break;
}
processChildren(c, latLngRect, queue, cellIds);
}
}
private static void processChildren(S2CellId parent, S2LatLngRect latLngRect,
ConcurrentLinkedQueue<S2CellId> queue, ArrayList<S2CellId> cellIds) {
List<S2CellId> children = new ArrayList<S2CellId>(4);
for (S2CellId c = parent.childBegin(); !c.equals(parent.childEnd()); c = c.next()) {
if (containsGeodataToFind(c, latLngRect)) {
children.add(c);
}
}
/*
* TODO: Need to update the strategy!
*
* Current strategy:
* 1 or 2 cells contain cellIdToFind: Traverse the children of the cell.
* 3 cells contain cellIdToFind: Add 3 cells for result.
* 4 cells contain cellIdToFind: Add the parent for result.
*
* ** All non-leaf cells contain 4 child cells.
*/
if (children.size() == 1 || children.size() == 2) {
for (S2CellId child : children) {
if (child.isLeaf()) {
cellIds.add(child);
} else {
queue.add(child);
}
}
} else if (children.size() == 3) {
cellIds.addAll(children);
} else if (children.size() == 4) {
cellIds.add(parent);
} else {
assert false; // This should not happen.
}
}
public static long generateGeohash(GeoPoint geoPoint) {
S2LatLng latLng = S2LatLng.fromDegrees(geoPoint.getLatitude(), geoPoint.getLongitude());
S2Cell cell = new S2Cell(latLng);
S2CellId cellId = cell.id();
return cellId.id();
}
public static long generateHashKey(long geohash, int hashKeyLength) {
if (geohash < 0) {
// Counteract "-" at beginning of geohash.
hashKeyLength++;
}
String geohashString = String.valueOf(geohash);
long denominator = (long) Math.pow(10, geohashString.length() - hashKeyLength);
return geohash / denominator;
}
}