com.bc.inventory.utils.S2Integer.java Source code

Java tutorial

Introduction

Here is the source code for com.bc.inventory.utils.S2Integer.java

Source

/*
 * Copyright (C) 2015 Brockmann Consult GmbH (info@brockmann-consult.de)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option)
 * any later version.
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, see http://www.gnu.org/licenses/
 */

package com.bc.inventory.utils;

import com.google.common.geometry.S2CellId;
import com.google.common.geometry.S2CellUnion;
import com.google.common.geometry.S2LatLng;
import com.google.common.geometry.S2Polygon;
import com.google.common.geometry.S2RegionCoverer;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * S2 methods dealing with a resolution that fits into an integer (32 bit)
 */
public class S2Integer {

    public static int asInt(S2CellId s2CellId) {
        if (s2CellId.level() > 13) {
            s2CellId = s2CellId.parent(13);
        }
        return (int) (s2CellId.id() >>> 34);
    }

    public static int asIntAtLevel(S2CellId s2CellId, int level) {
        if (s2CellId.level() > level) {
            s2CellId = s2CellId.parent(level);
        }
        return (int) (s2CellId.id() >>> (64 - 3 - (2 * level)));
    }

    public static strictfp boolean containsCellId(final int[] intCellIds, final S2CellId s2CellId) {
        return containsCellId(intCellIds, asInt(s2CellId));
    }

    public static strictfp boolean containsCellId(final int[] intCellIds, final int s2CellIdInt) {
        if (rangeMin(intCellIds[0]) > s2CellIdInt) {
            return false;
        }
        if (rangeMax(intCellIds[intCellIds.length - 1]) < s2CellIdInt) {
            return false;
        }
        int pos = Arrays.binarySearch(intCellIds, s2CellIdInt);
        if (pos < 0) {
            pos = -pos - 1;
        }

        return pos < intCellIds.length && rangeMin(intCellIds[pos]) <= s2CellIdInt
                || pos != 0 && rangeMax(intCellIds[pos - 1]) >= s2CellIdInt;
    }

    public static strictfp boolean intersectsCellId(final int[] intCellIds, final int s2CellIdInt) {
        int pos = Arrays.binarySearch(intCellIds, s2CellIdInt);
        if (pos < 0) {
            pos = -pos - 1;
        }

        return pos < intCellIds.length && rangeMin(intCellIds[pos]) <= rangeMax(s2CellIdInt)
                || pos != 0 && rangeMax(intCellIds[pos - 1]) >= rangeMin(s2CellIdInt);
    }

    public static int rangeMin(int s2cell) {
        return s2cell - (lowestOnBit(s2cell) - 1);
    }

    public static int rangeMax(int s2cell) {
        return s2cell + (lowestOnBit(s2cell) - 1);
    }

    public static int lowestOnBit(int s2cell) {
        return s2cell & -s2cell;
    }

    public static int[] cellUnion2Ints(S2CellUnion cellUnion) {
        int[] intIds;
        ArrayList<S2CellId> s2CellIds = cellUnion.cellIds();
        intIds = new int[s2CellIds.size()];
        for (int i = 0; i < intIds.length; i++) {
            intIds[i] = S2Integer.asInt(s2CellIds.get(i));
        }
        return intIds;
    }

    public static boolean intersectsCellUnion(int[] c1, int[] c2) {
        for (int s2CellIdInt : c2) {
            if (S2Integer.intersectsCellId(c1, s2CellIdInt)) {
                return true;
            }
        }
        return false;
    }

    public static boolean intersectsCellUnionFast(int[] c1, int[] c2) {
        int i = 0;
        int j = 0;

        while (i < c1.length && j < c2.length) {
            int imin = rangeMin(c1[i]);
            int jmin = rangeMin(c2[j]);
            if (imin > jmin) {
                // Either j->contains(*i) or the two cells are disjoint.
                if (c1[i] <= rangeMax(c2[j])) {
                    return true;
                } else {
                    // Advance "j" to the first cell possibly contained by *i.
                    j = indexedBinarySearch(c2, imin, j + 1);
                    // The previous cell *(j-1) may now contain *i.
                    if (c1[i] <= rangeMax(c2[j - 1])) {
                        --j;
                    }
                }
            } else if (jmin > imin) {
                // Identical to the code above with "i" and "j" reversed.
                if (c2[j] <= rangeMax(c1[i])) {
                    return true;
                } else {
                    i = indexedBinarySearch(c1, jmin, i + 1);
                    if (c2[j] <= rangeMax(c1[i - 1])) {
                        --i;
                    }
                }
            } else {
                // "i" and "j" have the same range_min(), so one contains the other.
                return true;
            }
        }
        return false;
    }

    /**
     * Just as normal binary search, except that it allows specifying the starting
     * value for the lower bound.
     *
     * @return The position of the searched element in the list (if found), or the
     * position where the element could be inserted without violating the
     * order.
     */
    private static int indexedBinarySearch(int[] l, int key, int low) {
        int high = l.length - 1;

        while (low <= high) {
            int mid = (low + high) >> 1;
            int midVal = l[mid];

            if (midVal < key) {
                low = mid + 1;
            } else if (midVal > key) {
                high = mid - 1;
            } else {
                return mid; // key found
            }
        }
        return low; // key not found
    }

    public static Coverage createS2IntCoverage(S2Polygon s2polygon, int maxLevel) {
        return new S2Integer.Coverage(createS2IntIds(s2polygon, maxLevel));
    }

    public static int[] createS2IntIds(S2Polygon s2polygon, int maxLevel) {
        return cellUnion2Ints(createCellUnion(s2polygon, maxLevel));
    }

    public static S2CellUnion createCellUnion(S2Polygon s2polygon, int maxLevel) {
        S2RegionCoverer coverer = new S2RegionCoverer();
        coverer.setMinLevel(0);
        coverer.setMaxLevel(maxLevel);
        coverer.setMaxCells(500);
        return coverer.getCovering(s2polygon);
    }

    public static class Coverage {

        public final int[] intIds;

        public Coverage(int... intIds) {
            this.intIds = intIds;
        }

        @Override
        public boolean equals(Object other) {
            if (this == other)
                return true;
            if (!(other instanceof Coverage))
                return false;
            return Arrays.equals(intIds, ((Coverage) other).intIds);
        }

        @Override
        public int hashCode() {
            return Arrays.hashCode(intIds);
        }
    }

    public static void main(String[] args) {
        S2LatLng s2LatLng = S2LatLng.fromDegrees(42, 10);
        System.out.println("s2LatLng = " + s2LatLng);
        S2CellId s2CellId = S2CellId.fromLatLng(s2LatLng);
        System.out.println("s2CellId = " + s2CellId);
        S2CellId s2CellId13 = s2CellId.parent(13);
        System.out.println("s2CellId13 = " + s2CellId13);

        System.out.println("s2cellId = " + Long.toBinaryString(s2CellId.id()));
        System.out.println("s2cellId13 = " + Long.toBinaryString(s2CellId13.id()));
        System.out.println("s2cellIdInt = " + Long.toBinaryString(asInt(s2CellId)));
    }
}