content: // ===============================================================================
  // Authors: AFRL/RQQD
  // Organization: Air Force Research Laboratory, Aerospace Systems Directorate, Power and Control Division
  // 
  // Copyright (c) 2017 Government of the United State of America, as represented by
  // the Secretary of the Air Force.  No copyright is claimed in the United States under
  // Title 17, U.S. Code.  All Other Rights Reserved.
  // ===============================================================================
  
  /*
   * GRAL: GRAphing Library for Java(R)
   *
   * (C) Copyright 2009-2013 Erich Seifert <dev[at]erichseifert.de>,
   * Michael Seifert <mseifert[at]error-reports.org>
   *
   * This file is part of GRAL.
   *
   * GRAL 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 3 of the License, or
   * (at your option) any later version.
   *
   * GRAL 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.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with GRAL.  If not, see <http://www.gnu.org/licenses/>.
   */
  package de.erichseifert.gral.util;
  
  import java.awt.geom.Point2D;
  import java.io.Serializable;
  import java.text.MessageFormat;
  import java.util.Arrays;
  
  /**
   * Class for storing n-dimensional points.
   * @param <T> Data type of the coordinates.
   */
  public class PointND<T extends Number> implements Serializable {
  	/** Version id for serialization. */
  	private static final long serialVersionUID = 3552680202450906771L;
  
  	/** Constant for accessing x-coordinate. */
  	public static final int X = 0;
  	/** Constant for accessing y-coordinate. */
  	public static final int Y = 1;
  	/** Constant for accessing z-coordinate. */
  	public static final int Z = 2;
  
  	/** Coordinates along the axes that describe this point. */
  	private final T[] coordinates;
  
  	/**
  	 * Constructor that initializes the point with a list of coordinates.
  	 * @param coordinates Coordinate values.
  	 */
  	public PointND(T... coordinates) {
  		this.coordinates = Arrays.copyOf(coordinates, coordinates.length);
  	}
  
  	/**
  	 * Returns the number of dimensions.
  	 * @return Number of dimensions.
  	 */
  	public int getDimensions() {
  		return coordinates.length;
  	}
  
  	/**
  	 * Returns the value of a specified dimension.
  	 * @param dimension Dimension.
  	 * @return Coordinate value.
  	 */
  	public T get(int dimension) {
  		return coordinates[dimension];
  	}
  
  	/**
  	 * Sets the value of a specified dimension.
  	 * @param dimension Dimension.
  	 * @param coordinate New coordinate value.
  	 */
  	public void set(int dimension, T coordinate) {
  		coordinates[dimension] = coordinate;
  	}
  
  	/**
  	 * Sets all coordinate values at once.
  	 * @param coordinates Coordinate values.
  	 */
  	public void setLocation(T... coordinates) {
  		if (getDimensions() != coordinates.length) {
  			throw new IllegalArgumentException(MessageFormat.format(
  				"Wrong number of dimensions: Expected {0,number,integer} values, got {1,number,integer}.", //$NON-NLS-1$
  				getDimensions(), coordinates.length));
  		}
  		System.arraycopy(coordinates, 0, this.coordinates, 0, getDimensions());
  	}
  
  	/**
  	 * Creates a two-dimensional point from the specified dimensions.
  	 * @param dimX Dimension for x coordinate.
  	 * @param dimY Dimension for y coordinate.
  	 * @return Two-dimensional point.
  	 */
  	public Point2D getPoint2D(int dimX, int dimY) {
  		if (getDimensions() < 2) {
  			throw new ArrayIndexOutOfBoundsException(
  					"Can't create two-dimensional point from " + //$NON-NLS-1$
  					getDimensions() + "D data."); //$NON-NLS-1$
  		}
  		return new Point2D.Double(
  				get(dimX).doubleValue(), get(dimY).doubleValue());
  	}
  
  	/**
  	 * Creates a two-dimensional point from dimensions 0 and 1.
  	 * @return Two-dimensional point.
  	 */
  	public Point2D getPoint2D() {
  		return getPoint2D(X, Y);
  	}
  
  	@Override
  	public String toString() {
  		return getClass().getName() + Arrays.deepToString(coordinates);
  	}
  
  	@Override
  	public boolean equals(Object obj) {
  		if (!(obj instanceof PointND<?>)) {
  			return false;
  		}
  		PointND<?> p = (PointND<?>) obj;
  		if (getDimensions() != p.getDimensions()) {
  			return false;
  		}
  		for (int dim = 0; dim < coordinates.length; dim++) {
  			Number dimA = get(dim);
  			Number dimB = p.get(dim);
  			if (dimA != null && dimB != null) {
  				if (!dimA.equals(dimB)) {
  					return false;
  				}
  			} else if (dimA != dimB) {
  				return false;
  			}
  		}
  		return true;
  	}
  
  	@Override
  	public int hashCode() {
  		int hashCode = 0;
  		for (T coordinate : coordinates) {
  			hashCode ^= coordinate.hashCode();
  		}
  		return hashCode;
  	}
  
  }
  