package org.djutils.draw.point; import java.awt.geom.Point2D; import java.util.Arrays; import java.util.Iterator; import org.djutils.draw.DrawRuntimeException; import org.djutils.draw.Drawable3d; import org.djutils.draw.Space3d; import org.djutils.draw.bounds.Bounds3d; import org.djutils.exceptions.Throw; /** * A Point3d is an immutable point with an x, y, and z coordinate, stored with double precision. It differs from many Point * implementations by being immutable. *
* Copyright (c) 2020-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See DJUTILS License.
*
fraction
is between 0 and 1, it
* is an interpolation, otherwise an extrapolation. If fraction
is 0; this
Point is
* returned; if fraction
is 1, the other point
is returned
* @return P; the point that is fraction
away on the line between this point and the other point
* @throws NullPointerException when point is null
* @throws IllegalArgumentException when fraction is NaN
*/
public Point3d interpolate(final Point3d point, final double fraction)
{
Throw.whenNull(point, "point cannot be null");
Throw.when(Double.isNaN(fraction), IllegalArgumentException.class, "fraction must be a number (not NaN)");
return new Point3d((1.0 - fraction) * getX() + fraction * point.getX(),
(1.0 - fraction) * getY() + fraction * point.getY(), (1.0 - fraction) * getZ() + fraction * point.getZ());
}
/**
* A comparison with another point that returns true of each of the coordinates is less than epsilon apart.
* @param other Point; the point to compare with
* @param epsilon double; the upper bound of difference for one of the coordinates
* @return boolean; true if both x, y and z (if a Point3d) are less than epsilon apart, otherwise false
* @throws NullPointerException when point is null
*/
public boolean epsilonEquals(final Point3d other, final double epsilon)
{
Throw.whenNull(other, "other point cannot be null");
if (Math.abs(getX() - other.getX()) > epsilon)
{
return false;
}
if (Math.abs(getY() - other.getY()) > epsilon)
{
return false;
}
if (Math.abs(getZ() - other.getZ()) > epsilon)
{
return false;
}
return true;
}
/** {@inheritDoc} */
@Override
public Bounds3d getBounds()
{
return new Bounds3d(this);
}
/**
* Return the direction of the point in radians with respect to the origin, ignoring the z-coordinate.
* @return double; the direction of the projection of the point in the x-y plane with respect to the origin, in radians
*/
final double horizontalDirection()
{
return Math.atan2(getY(), getX());
}
/**
* Return the direction to another point, in radians, ignoring the z-coordinate.
* @param point Point<?>; the other point
* @return double; the direction of the projection of the point in the x-y plane to another point, in radians
* @throws NullPointerException when point
is null
*/
final double horizontalDirection(final Point3d point) throws NullPointerException
{
Throw.whenNull(point, "point cannot be null");
return Math.atan2(point.getY() - getY(), point.getX() - getX());
}
/**
* Return the squared distance between the coordinates of this point and the provided point, ignoring the z-coordinate.
* @param point Point2d; the other point
* @return double; the squared distance between this point and the other point, ignoring the z-coordinate
* @throws NullPointerException when point is null
*/
final double horizontalDistanceSquared(final Point3d point)
{
Throw.whenNull(point, "point cannot be null");
double dx = getX() - point.getX();
double dy = getY() - point.getY();
return dx * dx + dy * dy;
}
/**
* Return the Euclidean distance between this point and the provided point, ignoring the z-coordinate.
* @param point Point2d; the other point
* @return double; the Euclidean distance between this point and the other point, ignoring the z-coordinate
* @throws NullPointerException when point is null
*/
final double horizontalDistance(final Point3d point)
{
return Math.sqrt(horizontalDistanceSquared(point));
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("checkstyle:designforextension")
public String toString()
{
return String.format("(%f,%f,%f)", getX(), getY(), getZ());
}
/** {@inheritDoc} */
@Override
public String toString(final int fractionDigits)
{
int digits = fractionDigits < 0 ? 0 : fractionDigits;
String format = String.format("(%%.%1$df,%%.%1$df,%%.%1$df)", digits);
return String.format(format, getX(), getY(), getZ());
}
/** {@inheritDoc} */
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(this.x);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(this.y);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(this.z);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
/** {@inheritDoc} */
@SuppressWarnings("checkstyle:needbraces")
@Override
public boolean equals(final Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point3d other = (Point3d) obj;
if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x))
return false;
if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y))
return false;
if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z))
return false;
return true;
}
}