All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.anwiba.spatial.coordinate.CoordinateUtilities Maven / Gradle / Ivy

There is a newer version: 1.2.50
Show newest version
/*
 * #%L
 * anwiba commons core
 * %%
 * Copyright (C) 2007 - 2018 Andreas W. Bartels
 * %%
 * This program 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, either version 2.1 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

package net.anwiba.spatial.coordinate;

import static net.anwiba.commons.utilities.math.MathWrapper.*;

import net.anwiba.spatial.coordinate.calculator.DefaultCoordinateDistanceCalculator;
import net.anwiba.spatial.coordinate.calculator.ICoordinateDistanceCalculator;
import net.anwiba.spatial.coordinate.calculator.RobustDeterminantCalculator;
import net.anwiba.spatial.coordinate.calculator.SmallPointCalculator;

public class CoordinateUtilities {

  public static ICoordinate[] getCoordinates(final ICoordinateSequence sequence) {
    final ICoordinate[] coordinates = new ICoordinate[sequence.getNumberOfCoordinates()];
    for (int i = 0; i < coordinates.length; i++) {
      coordinates[i] = sequence.getCoordinateN(i);
    }
    return coordinates;
  }

  public static double calculateArea(final ICoordinateSequence sequence) {
    if (sequence == null || sequence.getNumberOfCoordinates() < 3) {
      return 0;
    }
    double sum = 0;
    for (int i = 0; i < sequence.getNumberOfCoordinates(); i++) {
      final ICoordinate prior = getPrior(sequence, i);
      final ICoordinate coordinate = sequence.getCoordinateN(i);
      final ICoordinate next = getNext(sequence, i);
      sum += coordinate.getXValue() * (prior.getYValue() - next.getYValue());
    }
    return sum / 2;
  }

  private static ICoordinate getPrior(final ICoordinateSequence sequence, final int i) {
    if (i == 0) {
      return sequence.getCoordinateN(sequence.getNumberOfCoordinates() - 1);
    }
    return sequence.getCoordinateN(i - 1);
  }

  private static ICoordinate getNext(final ICoordinateSequence sequence, final int i) {
    if (i + 1 == sequence.getNumberOfCoordinates()) {
      return sequence.getCoordinateN(0);
    }
    return sequence.getCoordinateN(i + 1);
  }

  public static double calculateLength(final ICoordinateSequence sequence) {
    double sum = 0;
    ICoordinate prior = null;
    for (final ICoordinate coordinate : sequence.getCoordinates()) {
      if (prior != null) {
        sum += calculateDistance(prior, coordinate);
      }
      prior = coordinate;
    }
    return sum;
  }

  public static double calculateDistance(final ICoordinate c0, final ICoordinate c1) {
    final double sum = pow(c1.getXValue() - c0.getXValue(), 2) + pow(c1.getYValue() - c0.getYValue(), 2);
    return sqrt(sum);
  }

  public static ICoordinate calculateSmallPoint(
      final ICoordinate c0,
      final ICoordinate c1,
      final double s,
      final double r) {
    return new SmallPointCalculator(c0, c1).calculate(s, r);
  }

  final static ICoordinateDistanceCalculator coordinateDistanceCalculator = new DefaultCoordinateDistanceCalculator();

  public static ICoordinate calculateSmallPoint(final ICoordinate c0, final ICoordinate c1, final double s)
      throws CoordinateCalculationException {
    final double x0 = c0.getXValue();
    final double y0 = c0.getYValue();
    if (c1.touch(x0, y0)) {
      throw new CoordinateCalculationException("base points are equal"); //$NON-NLS-1$
    }
    final double x1 = c1.getXValue();
    final double y1 = c1.getYValue();
    final double d = coordinateDistanceCalculator.calculateDistance(x0, y0, x1, y1);
    final double xs = x0 + (x1 - x0) / d * s;
    final double ys = y0 + (y1 - y0) / d * s;
    if (c0.getDimension() > 2 && c1.getDimension() > 2) {
      final double z0 = c0.getZValue();
      final double z1 = c1.getZValue();
      final double zs = z0 + (z1 - z0) / d * s;
      return new Coordinate(xs, ys, zs, false);
    }
    return new Coordinate(xs, ys);
  }

  public static ICoordinate calculateBasePoint(
      final ICoordinate c0,
      final ICoordinate c1,
      final ICoordinate coordinate) {
    final double x0 = c0.getXValue();
    final double y0 = c0.getYValue();
    if (c1.touch(x0, y0)) {
      return new Coordinate(x0, y0);
    }
    final double x1 = c1.getXValue();
    final double y1 = c1.getYValue();
    final double x2 = coordinate.getXValue();
    final double y2 = coordinate.getYValue();
    if (x0 == x1) {
      return new Coordinate(x0, y2);
    }
    if (y0 == y1) {
      return new Coordinate(x2, y0);
    }
    final double m = (y1 - y0) / (x1 - x0);
    final double xs = (m * (y2 - y0) + x2 - x0) / (m * m + 1) + x0;
    final double ys = (xs - x0) * m + y0;
    return new Coordinate(xs, ys);
  }

  public static ICoordinate calculateIntersection(
      final ICoordinate c0,
      final ICoordinate c1,
      final ICoordinate c2,
      final ICoordinate c3)
      throws CoordinateCalculationException {
    final double x0 = c0.getXValue();
    final double y0 = c0.getYValue();
    if (c1.touch(x0, y0)) {
      throw new CoordinateCalculationException("base points 0 and 1 are equal"); //$NON-NLS-1$
    }
    final double x1 = c1.getXValue();
    final double y1 = c1.getYValue();
    final double x2 = c2.getXValue();
    final double y2 = c2.getYValue();
    if (c3.touch(x2, y2)) {
      throw new CoordinateCalculationException("base points 2 and 3 are equal"); //$NON-NLS-1$
    }
    final double x3 = c3.getXValue();
    final double y3 = c3.getYValue();
    if ((x0 == x1 && x2 == x3) || (y0 == y1 && y2 == y3)) {
      throw new CoordinateCalculationException("lines are parallel"); //$NON-NLS-1$
    }
    if (x0 == x1) {
      final double m1 = (y3 - y2) / (x3 - x2);
      return new Coordinate(x0, y2 + m1 * (x0 - x2));
    }
    if (x2 == x3) {
      final double m0 = (y1 - y0) / (x1 - x0);
      return new Coordinate(x2, y0 + m0 * (x3 - x0));
    }
    final double m0 = (y1 - y0) / (x1 - x0);
    final double m1 = (y3 - y2) / (x3 - x2);
    final double d = (y0 - y2 - m0 * (x0 - x2)) / (m1 - m0);
    return new Coordinate(d + x2, y2 + m1 * d);
  }

  public static ICoordinate getAvarageCoordinate(final ICoordinate... coordinates) {
    if (coordinates.length == 1) {
      return coordinates[0];
    }
    ICoordinate centroid = null;
    for (int i = 0; i < coordinates.length; i++) {
      final ICoordinate coordinate = coordinates[i];
      if (centroid == null) {
        centroid = coordinate;
        continue;
      }
      centroid = CoordinateUtilities.getAvarageCoordinate(centroid, coordinate, i + 1);
    }
    return centroid;
  }

  public static ICoordinate getAvarageCoordinate(final ICoordinate c0, final ICoordinate c1, final int n) {
    if (c0.isMeasured() && c1.isMeasured()) {
      final double[] values = new double[min(c0.getDimension(), c1.getDimension()) + 1];
      for (int i = 0; i < values.length - 1; i++) {
        values[i] = getAvarageValue(c0.getValue(i), c1.getValue(i), n);
      }
      values[values.length - 1] = getAvarageValue(c0.getMeasuredValue(), c1.getMeasuredValue(), n);
      return new Coordinate(values, true);
    }
    final double[] values = new double[min(c0.getDimension(), c1.getDimension())];
    for (int i = 0; i < values.length; i++) {
      values[i] = getAvarageValue(c0.getValue(i), c1.getValue(i), n);
    }
    return new Coordinate(values, false);
  }

  public static double getAvarageValue(final double m1, final double d, final int n) {
    return m1 + ((d - m1) / n);
  }

  public static boolean isInterior(final ICoordinate c0, final ICoordinate c1, final ICoordinate coordinate) {
    final double xmin = min(c0.getXValue(), c1.getXValue());
    final double xmax = max(c0.getXValue(), c1.getXValue());
    final double xc = coordinate.getXValue();
    if (!(xmin <= xc && xc <= xmax)) {
      return false;
    }
    final double ymin = min(c0.getYValue(), c1.getYValue());
    final double ymax = max(c0.getYValue(), c1.getYValue());
    final double yc = coordinate.getYValue();
    if (!(ymin <= yc && yc <= ymax)) {
      return false;
    }
    if (xmin == xmax) {
      return true;
    }
    if (ymin == ymax) {
      return true;
    }
    final double m1 = (c1.getYValue() - c0.getYValue()) / (c1.getXValue() - c0.getXValue());
    final double m2 = (yc - c0.getYValue()) / (xc - c0.getXValue());
    final double abs = abs(m1 - m2);
    return abs < 0.00000001;
  }

  public static boolean isPointInRing(final ICoordinate coordinate, final ICoordinateSequence ring) {
    final double x = coordinate.getXValue();
    final double y = coordinate.getYValue();
    boolean isInside = false;
    ICoordinate previous = null;
    for (final ICoordinate next : ring.getCoordinates()) {
      if (previous == null) {
        previous = next;
        continue;
      }
      final double yp = previous.getYValue();
      final double yn = next.getYValue();
      if (yp > y && yn <= y || yn > y && yp <= y) {
        final double y0 = yp - y;
        final double y1 = yn - y;
        if (RobustDeterminantCalculator.signOfDet(previous.getXValue() - x, y0, next.getXValue() - x, y1)
            / (y1 - y0) > 0.0) {
          if (y == yn) {
            continue;
          }
          isInside = !isInside;
        }
      }
      previous = next;
    }
    return isInside;
  }

  public static boolean interact(
      final ICoordinate coordinate,
      final ICoordinate otherCoordinate,
      final double tolerance) {
    final double abs = abs(calculateDistance(coordinate, otherCoordinate));
    if (Double.isNaN(tolerance) || tolerance == 0) {
      final double cLog10 = max(log10(abs(coordinate.getXValue())), log10(abs(coordinate.getYValue())));
      final double log10 = log10(abs);
      return cLog10 - log10 > 12;
    }
    return tolerance > abs || (tolerance == 0 && abs == 0);
  }

  public static boolean isCrossing(
      final ICoordinate c0,
      final ICoordinate c1,
      final ICoordinate c2,
      final ICoordinate c3) {
    try {
      final ICoordinate crossPoint = calculateIntersection(c0, c1, c2, c3);
      if (isInsideRectangle(c0, c1, crossPoint) && isInsideRectangle(c2, c3, crossPoint)) {
        return true;
      }
      if ((c0.touch(crossPoint) || c1.touch(crossPoint)) && (c2.touch(crossPoint) || c3.touch(crossPoint))) {
        return true;
      }
      return false;
    } catch (final CoordinateCalculationException exception) {
      return false;
    }
  }

  public static boolean isInsideRectangle(final ICoordinate c0, final ICoordinate c1, final ICoordinate coordinate) {
    final double xmin = min(c0.getXValue(), c1.getXValue());
    final double xmax = max(c0.getXValue(), c1.getXValue());
    final double xc = coordinate.getXValue();
    if (!(xmin <= xc && xc <= xmax)) {
      return false;
    }
    final double ymin = min(c0.getYValue(), c1.getYValue());
    final double ymax = max(c0.getYValue(), c1.getYValue());
    final double yc = coordinate.getYValue();
    if (!(ymin <= yc && yc <= ymax)) {
      return false;
    }
    return true;
  }

  public static boolean isBetween(
      final ICoordinate c0,
      final ICoordinate c1,
      final ICoordinate coordinate,
      final double tolerance) {
    if (!EnvelopeUtilities.createEnvelope(EnvelopeUtilities.createEnvelope(c0, c1), tolerance).interact(coordinate)) {
      return false;
    } ;
    if (interact(coordinate, c0, tolerance)) {
      return true;
    }
    if (interact(coordinate, c1, tolerance)) {
      return true;
    }
    final ICoordinate base = calculateBasePoint(c0, c1, coordinate);
    if (interact(coordinate, base, tolerance)) {
      if (isInterior(c0, c1, base)) {
        return true;
      }
    }
    return false;
  }

  public static ICoordinate calculatePolarCoordinate(
      final ICoordinate coordinate,
      final double angel,
      final double distance) {
    return new Coordinate(
        (coordinate.getXValue() + distance * sin(angel)),
        (coordinate.getYValue() + distance * cos(angel)));
  }

  public static double calculateAngle(final ICoordinate c0, final ICoordinate c1) {
    final double a = c1.getXValue() - c0.getXValue();
    final double b = c1.getYValue() - c0.getYValue();
    if (a == 0) {
      if (b > 0) {
        return 0;
      }
      return PI;
    }
    if (b == 0) {
      if (a > 0) {
        return PI / 2;
      }
      return PI / 2 * 3;
    }
    final double alpha = atan(a / b);
    if (b < 0) {
      return PI + alpha;
    }
    if (a < 0) {
      return PI * 2 + alpha;
    }
    return alpha;
  }

  public static ICoordinate getMinimum(final ICoordinate coordinate, final ICoordinate other) {
    if (coordinate == null) {
      return other;
    }
    if (other == null) {
      return coordinate;
    }
    final double x = min(coordinate.getXValue(), other.getXValue());
    final double y = min(coordinate.getYValue(), other.getYValue());
    if (min(coordinate.getDimension(), other.getDimension()) == 2) {
      if (coordinate.isMeasured() && other.isMeasured()) {
        return new Coordinate(x, y, min(coordinate.getMeasuredValue(), other.getMeasuredValue()), true);
      }
      return new Coordinate(x, y);
    }
    if (coordinate.isMeasured() && other.isMeasured()) {
      return new Coordinate(
          x,
          y,
          min(coordinate.getZValue(), other.getZValue()),
          min(coordinate.getMeasuredValue(), other.getMeasuredValue()));
    }
    return new Coordinate(x, y, min(coordinate.getZValue(), other.getZValue()), false);
  }

  public static ICoordinate getMaximum(final ICoordinate coordinate, final ICoordinate other) {
    if (coordinate == null) {
      return other;
    }
    if (other == null) {
      return coordinate;
    }
    final double x = max(coordinate.getXValue(), other.getXValue());
    final double y = max(coordinate.getYValue(), other.getYValue());
    if (min(coordinate.getDimension(), other.getDimension()) == 2) {
      if (coordinate.isMeasured() && other.isMeasured()) {
        return new Coordinate(x, y, max(coordinate.getMeasuredValue(), other.getMeasuredValue()), true);
      }
      return new Coordinate(x, y);
    }
    if (coordinate.isMeasured() && other.isMeasured()) {
      return new Coordinate(
          x,
          y,
          max(coordinate.getZValue(), other.getZValue()),
          max(coordinate.getMeasuredValue(), other.getMeasuredValue()));
    }
    return new Coordinate(x, y, max(coordinate.getZValue(), other.getZValue()), false);
  }

  public static ICoordinate createAdapted(
      final ICoordinate coordinate,
      final int coordinateValueIndex,
      final double value) {
    final double[] values = coordinate.getValues();
    values[coordinateValueIndex] = value;
    return new Coordinate(values, coordinate.isMeasured());
  }

  public static ICoordinate getMaximum(final ICoordinate... coordinates) {
    ICoordinate result = null;
    for (final ICoordinate coordinate : coordinates) {
      if (result == null) {
        result = coordinate;
        continue;
      }
      result = CoordinateUtilities.getMaximum(result, coordinate);
    }
    return result;
  }

  public static ICoordinate getMinimum(final ICoordinate... coordinates) {
    ICoordinate result = null;
    for (final ICoordinate coordinate : coordinates) {
      if (result == null) {
        result = coordinate;
        continue;
      }
      result = CoordinateUtilities.getMinimum(result, coordinate);
    }
    return result;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy