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

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

There is a newer version: 1.2.50
Show newest version
/*
 * #%L
 * anwiba spatial
 * %%
 * Copyright (C) 2007 - 2019 Andreas 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%
 */
// Copyright (c) 2006 by Andreas W. Bartels
package net.anwiba.spatial.coordinate;

import java.util.Arrays;

import net.anwiba.commons.lang.object.ObjectUtilities;
import net.anwiba.commons.utilities.ArrayUtilities;

public class Coordinate implements ICoordinate {

  private static final long serialVersionUID = 1L;
  private final boolean isMeasured;
  private final double[] values;
  private int measuredIndex;

  public Coordinate(final double x, final double y) {
    this(new double[] { x, y }, false);

  }

  public Coordinate(final double x, final double y, final double n, final boolean isMeasured) {
    this(new double[] { x, y, n }, isMeasured);

  }

  public Coordinate(final double x, final double y, final double z, final double m) {
    this(new double[] { x, y, z, m }, true);
  }

  public Coordinate(final double[] values, final boolean isMeasured) {
    this.values = ArrayUtilities.copy(values);
    if (this.values.length < 2 || isMeasured && this.values.length < 3) {
      throw new IllegalArgumentException("Coordinate dimension is lower than 2"); //$NON-NLS-1$
    }
    if (isMeasured) {
      this.measuredIndex = this.values.length - 1;
    } else {
      this.measuredIndex = 0;
    }
    this.isMeasured = isMeasured;
  }

  @Override
  public int getDimension() {
    return this.isMeasured ? this.values.length - 1 : this.values.length;
  }

  @Override
  public boolean isMeasured() {
    return this.isMeasured;
  }

  @Override
  public double getValue(final int index) {
    return getOrdinate(index, "Coordinate has no value at index " + index); //$NON-NLS-1$
  }

  @Override
  public double getXValue() {
    return getOrdinate(X, "Coordinate has no x value"); //$NON-NLS-1$
  }

  @Override
  public double getYValue() {
    return getOrdinate(Y, "Coordinate has no y value"); //$NON-NLS-1$
  }

  @Override
  public double getZValue() {
    return getOrdinate(Z, "Coordinate has no z value"); //$NON-NLS-1$
  }

  private double getOrdinate(final int index, final String message) {
    try {
      final int p = this.isMeasured ? this.values.length - 2 : this.values.length - 1;
      if (p >= index) {
        return this.values[index];
      }
      throw new RuntimeException(message);
    } catch (final Exception exception) {
      throw new RuntimeException(message, exception);
    }
  }

  @Override
  public double getMeasuredValue() {
    if (!this.isMeasured) {
      throw new RuntimeException("Coordinate has no measured value"); //$NON-NLS-1$
    }
    return this.values[this.measuredIndex];
  }

  @Override
  public double[] getValues() {
    return ArrayUtilities.copy(this.values);
  }

  @Override
  public ICoordinate add(final ICoordinate other) {
    return calculate(other, (v, o) -> v + o);
  }

  @Override
  public ICoordinate subtract(final ICoordinate other) {
    return calculate(other, (v, o) -> v - o);
  }

  interface IDoubleOperator {

    double operat(double value, double other);

  }

  private ICoordinate calculate(final ICoordinate other, final IDoubleOperator operator) {
    final double[] result = new double[2
        + (getDimension() > 2 && other.getDimension() > 2 ? 1 : 0)
        + (isMeasured() && other.isMeasured() ? 1 : 0)];
    int i;
    for (i = 0; i < 2; i++) {
      result[i] = operator.operat(getValue(i), other.getValue(i));
    }
    if (getDimension() > 2 && other.getDimension() > 2) {
      result[i] = operator.operat(getZValue(), other.getZValue());
    }
    if (isMeasured() && other.isMeasured()) {
      result[i] = operator.operat(getMeasuredValue(), other.getMeasuredValue());
    }
    return new Coordinate(result, isMeasured() && other.isMeasured());
  }

  @Override
  public boolean touch(final ICoordinate other) {
    for (int i = 0; i < Math.min(other.getDimension(), getDimension()); i++) {
      if (other.getValue(i) != this.values[i]) {
        return false;
      }
    }
    return true;
  }

  @Override
  public boolean touch(final double x, final double y) {
    return x == this.values[ICoordinate.X] && y == this.values[ICoordinate.Y];
  }

  @Override
  public boolean equals(final Object object) {
    if (object == null || !(object instanceof ICoordinate)) {
      return false;
    }
    if (object instanceof Coordinate) {
      final Coordinate other = (Coordinate) object;
      return (this.isMeasured == other.isMeasured)
          && ObjectUtilities.equals(this.values, other.values);
    }
    final ICoordinate other = (ICoordinate) object;
    return (this.isMeasured == other.isMeasured())
        && ObjectUtilities.equals(this.values, other.getValues());
  }

  @Override
  public int hashCode() {
    long bits = 0;
    for (final double value : this.values) {
      bits ^= java.lang.Double.doubleToLongBits(value) * 31;
    }
    return (int) (bits ^ (bits >> 32));
  }

  @Override
  public int compareTo(final ICoordinate coordinate) {
    final double[] otherValues = coordinate.getValues();
    for (int i = 0; i < Math.min(otherValues.length, this.values.length); i++) {
      if (this.values[i] < otherValues[i]) {
        return -1;
      }
      if (this.values[i] > otherValues[i]) {
        return 1;
      }
    }
    return 0;
  }

  @Override
  public String toString() {
    return "Coordinate[" + Arrays.toString(getValues()) + "," + isMeasured() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy