/** * H2GIS is a library that brings spatial support to the H2 Database Engine * <http://www.h2database.com>. H2GIS is developed by CNRS * <http://www.cnrs.fr/>. * * This code is part of the H2GIS project. H2GIS is free software; * you can redistribute it and/or modify it under the terms of the GNU * Lesser General Public License as published by the Free Software Foundation; * version 3.0 of the License. * * H2GIS 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 Lesser General Public License * for more details <http://www.gnu.org/licenses/>. * * * For more information, please consult: <http://www.h2gis.org/> * or contact directly: info_at_h2gis.org */ package org.h2gis.drivers.utility; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Polygon; /** * This utility class provides some useful methods related to JTS {@link com.vividsolutions.jts.geom.Coordinate} objects. * * @author Erwan Bocher */ public final class CoordinatesUtils { /** * Interpolates a z value (linearly) between the two coordinates. * * @param firstCoordinate * @param lastCoordinate * @param toBeInterpolated * @return */ public static double interpolate(Coordinate firstCoordinate, Coordinate lastCoordinate, Coordinate toBeInterpolated) { if (Double.isNaN(firstCoordinate.z)) { return Double.NaN; } if (Double.isNaN(lastCoordinate.z)) { return Double.NaN; } return firstCoordinate.z + (lastCoordinate.z - firstCoordinate.z) * firstCoordinate.distance(toBeInterpolated) / (firstCoordinate.distance(toBeInterpolated) + toBeInterpolated.distance(lastCoordinate)); } public static boolean contains(Coordinate[] coords, Coordinate coord) { for (Coordinate coordinate : coords) { if (Double.isNaN(coord.z)) { return coordinate.equals(coord); } else { return coordinate.equals3D(coord); } } return false; } /** * Checks if a coordinate array contains a specific coordinate. * * The equality is done only in 2D (z values are not checked). * * @param coords * @param coord * @return */ public static boolean contains2D(Coordinate[] coords, Coordinate coord) { for (Coordinate coordinate : coords) { if (coordinate.equals2D(coord)) { return true; } } return false; } /** * Check if a coordinate array contains a specific coordinate. * * The equality is done in 3D (z values ARE checked). * * @param coords * @param coord * @return */ public static boolean contains3D(Coordinate[] coords, Coordinate coord) { for (Coordinate coordinate : coords) { if (coordinate.equals3D(coord)) { return true; } } return false; } /** * Determine the min and max "z" values in an array of Coordinates. * * @param cs The array to search. * @return An array of size 2, index 0 is min, index 1 is max. */ public static double[] zMinMax(final Coordinate[] cs) { double zmin; double zmax; boolean validZFound = false; double[] result = new double[2]; zmin = Double.NaN; zmax = Double.NaN; double z; for (int t = cs.length - 1; t >= 0; t--) { z = cs[t].z; if (!(Double.isNaN(z))) { if (validZFound) { if (z < zmin) { zmin = z; } if (z > zmax) { zmax = z; } } else { validZFound = true; zmin = z; zmax = z; } } } result[0] = (zmin); result[1] = (zmax); return result; } /** * Find the furthest coordinate in a geometry from a base coordinate * * @param base * @param coords * @return the base coordinate and the target coordinate */ public static Coordinate[] getFurthestCoordinate(Coordinate base, Coordinate[] coords) { double distanceMax = Double.MIN_VALUE; Coordinate farCoordinate = null; for (Coordinate coord : coords) { double distance = coord.distance(base); if (distance > distanceMax) { distanceMax = distance; farCoordinate = coord; } } if (farCoordinate != null) { return new Coordinate[]{base, farCoordinate}; } else { return null; } } /** * Computes the length of a linestring specified by a sequence of points. * if a coordinate has a NaN z return 0. * * @param pts * the points specifying the linestring * @return the length of the linestring */ public static double length3D(CoordinateSequence pts) { // optimized for processing CoordinateSequences int n = pts.size(); if (n <= 1) { return 0.0; } double len = 0.0; Coordinate p = new Coordinate(); pts.getCoordinate(0, p); double x0 = p.x; double y0 = p.y; double z0 = p.z; if (Double.isNaN(z0)) { return 0.0; } for (int i = 1; i < n; i++) { pts.getCoordinate(i, p); double x1 = p.x; double y1 = p.y; double z1 = p.z; if (Double.isNaN(z1)) { return 0.0; } double dx = x1 - x0; double dy = y1 - y0; double dz = z1 - z0; len += Math.sqrt(dx * dx + dy * dy + dz * dz); x0 = x1; y0 = y1; z0 = z1; } return len; } /** * Returns the 3D length of the geometry * * * @param geom * @return */ public static double length3D(Geometry geom) { double sum = 0; for (int i = 0; i < geom.getNumGeometries(); i++) { Geometry subGeom = geom.getGeometryN(i); if (subGeom instanceof Polygon) { sum += length3D((Polygon) subGeom); } else if (subGeom instanceof LineString) { sum += length3D((LineString) subGeom); } } return sum; } /** * Returns the 3D perimeter of a line string. * * @param lineString * @return */ public static double length3D(LineString lineString) { return length3D(lineString.getCoordinateSequence()); } /** * Returns the 3D perimeter of a polygon * * @param polygon * @return */ public static double length3D(Polygon polygon) { double len = 0.0; len += length3D(polygon.getExteriorRing().getCoordinateSequence()); for (int i = 0; i < polygon.getNumInteriorRing(); i++) { len += length3D(polygon.getInteriorRingN(i)); } return len; } /** * Private constructor for utility class. */ private CoordinatesUtils() { } }