/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.server.spatial; import com.geophile.z.Space; import com.geophile.z.SpatialObject; import com.geophile.z.spatialobject.jts.JTS; import com.geophile.z.spatialobject.jts.JTSSpatialObject; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKBReader; import com.vividsolutions.jts.io.WKBWriter; import com.vividsolutions.jts.io.WKTReader; import com.vividsolutions.jts.io.WKTWriter; import java.util.logging.Level; /* The lat/lon coordinate system is - latitude: -90.0 to +90.0 - longitude: -180.0 to 180.0 with wraparound The interleave pattern is [lon, lat, lon, lat, ..., lon], reflecting the fact that longitude covers a numeric range twice that of latitude. */ public class Spatial { public static Space createLatLonSpace() { int[] interleave = new int[LAT_BITS + LON_BITS]; int dimension = 1; // Start with lon, as described above for (int d = 0; d < LAT_BITS + LON_BITS; d++) { interleave[d] = dimension; dimension = 1 - dimension; } return Space.newSpace(new double[]{MIN_LAT, MIN_LON}, new double[]{MAX_LAT, MAX_LON}, new int[]{LAT_BITS, LON_BITS}, interleave); } public static long shuffle(Space space, double x, double y) { com.geophile.z.spatialobject.d2.Point point = new com.geophile.z.spatialobject.d2.Point(x, y); long[] zValues = new long[1]; space.decompose(point, zValues); long z = zValues[0]; assert z != Space.Z_NULL; return z; } public static void shuffle(Space space, SpatialObject spatialObject, long[] zs) { space.decompose(spatialObject, zs); } public static byte[] serializeWKB(JTSSpatialObject spatialObject) { return io.get().wkbWriter().write(spatialObject.geometry()); } public static SpatialObject deserializeWKB(Space space, byte[] bytes) throws ParseException { Geometry geometry = io.get().wkbReader().read(bytes); return geometry instanceof Point ? JTS.spatialObject(space, (Point) geometry) : JTS.spatialObject(space, geometry); } public static String serializeWKT(JTSSpatialObject spatialObject) { return io.get().wktWriter().write(spatialObject.geometry()); } public static SpatialObject deserializeWKT(Space space, String string) throws ParseException { Geometry geometry = io.get().wktReader().read(string); return geometry instanceof Point ? JTS.spatialObject(space, (Point) geometry) : JTS.spatialObject(space, geometry); } static { // java.util.logging.Logger.getLogger("").setLevel(Level.FINE); } public static final int LAT_LON_DIMENSIONS = 2; public static final double MIN_LAT = -90; public static final double MAX_LAT = 90; public static final double MIN_LON = -180; public static final double MAX_LON = 180; private static final int LAT_BITS = 28; private static final int LON_BITS = 29; private static final ThreadLocal<IO> io = new ThreadLocal<IO>() { @Override protected IO initialValue() { return new IO(); } }; // Inner classes private static class IO { public WKBReader wkbReader() { if (wkbReader == null) { wkbReader = new WKBReader(factory); } return wkbReader; } public WKBWriter wkbWriter() { if (wkbWriter == null) { wkbWriter = new WKBWriter(); } return wkbWriter; } public WKTReader wktReader() { if (wktReader == null) { wktReader = new WKTReader(factory); } return wktReader; } public WKTWriter wktWriter() { if (wktWriter == null) { wktWriter = new WKTWriter(); } return wktWriter; } private final GeometryFactory factory = new GeometryFactory(); private WKBReader wkbReader; private WKBWriter wkbWriter; private WKTReader wktReader; private WKTWriter wktWriter; } }