/************************************************************************** OSMemory library for OSM data processing. Copyright (C) 2014 Aleś Bułojčyk <alex73mail@gmail.com> This 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 software 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 org.alex73.osmemory.geometry; import org.alex73.osmemory.IOsmNode; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Polygon; /** * Some base operations for cells. */ public class Fast { public static final int PARTS_COUNT_BYXY = 20; protected final int minx, maxx, miny, maxy, stepx, stepy; protected final Geometry polygon; protected final Cell[][] cached; public Fast(Geometry polygon) { if (polygon == null) { throw new IllegalArgumentException(); } this.polygon = polygon; Envelope bo = polygon.getEnvelopeInternal(); minx = (int) (bo.getMinX() / IOsmNode.DIVIDER) - 1; maxx = (int) (bo.getMaxX() / IOsmNode.DIVIDER) + 1; miny = (int) (bo.getMinY() / IOsmNode.DIVIDER) - 1; maxy = (int) (bo.getMaxY() / IOsmNode.DIVIDER) + 1; // can be more than 4-byte signed integer long dx = ((long) maxx) - ((long) minx); long dy = ((long) maxy) - ((long) miny); stepx = (int) (dx / PARTS_COUNT_BYXY + 1); stepy = (int) (dy / PARTS_COUNT_BYXY + 1); cached = new Cell[PARTS_COUNT_BYXY][]; for (int i = 0; i < cached.length; i++) { cached[i] = new Cell[PARTS_COUNT_BYXY]; } } public Geometry getGeometry() { return polygon; } public synchronized Cell getCellForPoint(int lat, int lon) { int x = lon; int y = lat; if (x < minx || x >= maxx || y < miny || y >= maxy) { return null; } int ix = (x - minx) / stepx; int iy = (y - miny) / stepy; return getCell(ix, iy); } public int getCellXForPoint(int lon) { int x = lon; if (x < minx) { return -1; } if (x >= maxx) { return PARTS_COUNT_BYXY; } return (x - minx) / stepx; } public int getCellYForPoint(int lat) { int y = lat; if (y < miny) { return -1; } if (y >= maxy) { return PARTS_COUNT_BYXY; } return (y - miny) / stepy; } public Cell getCell(int ix, int iy) { if (cached[ix][iy] != null) { return cached[ix][iy]; } synchronized (this) { if (cached[ix][iy] == null) { cached[ix][iy] = calcCell(ix, iy); } } return cached[ix][iy]; } protected Cell calcCell(int ix, int iy) { int ulx = minx + ix * stepx; int uly = miny + iy * stepy; double mix = ulx * IOsmNode.DIVIDER; double max = (ulx + stepx - 1) * IOsmNode.DIVIDER; double miy = uly * IOsmNode.DIVIDER; double may = (uly + stepy - 1) * IOsmNode.DIVIDER; Polygon p = GeometryHelper.createBoxPolygon(mix, max, miy, may); final Geometry intersection = polygon.intersection(p); if (intersection.isEmpty()) { return new Cell(ix, iy, true, false, intersection); } else if (intersection.equalsExact(p)) { return new Cell(ix, iy, false, true, intersection); } else { return new Cell(ix, iy, false, false, intersection); } } public static class Cell { private final int x, y; private final boolean empty, full; private final Geometry geom; public Cell(int x, int y, boolean empty, boolean full, Geometry geom) { this.x = x; this.y = y; this.empty = empty; this.full = full; this.geom = geom; } public boolean isEmpty() { return empty; } public boolean isFull() { return full; } public int getX() { return x; } public int getY() { return y; } public Geometry getGeom() { return geom; } } }