package org.djutils.draw.point; import java.awt.geom.Point2D; import java.util.Arrays; import java.util.Iterator; import org.djutils.base.AngleUtil; import org.djutils.draw.Directed2d; import org.djutils.draw.DrawRuntimeException; import org.djutils.exceptions.Throw; /** * The DirectedPoint2d is a point in a 2-dimensional space with a direction vector, which is specified in terms of its * counter-clockwise rotation around the point in radians. *
* 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 DirectedPoint2d; a new DirectedPoint2d at the requested fraction
* @throws NullPointerException when otherPoint is null
* @throws IllegalArgumentException when fraction is NaN
*/
public DirectedPoint2d interpolate(final DirectedPoint2d otherPoint, final double fraction)
throws NullPointerException, IllegalArgumentException
{
Throw.whenNull(otherPoint, "point cannot be null");
Throw.when(Double.isNaN(fraction), IllegalArgumentException.class, "fraction must be a number (not NaN)");
return new DirectedPoint2d((1.0 - fraction) * getX() + fraction * otherPoint.x,
(1.0 - fraction) * getY() + fraction * otherPoint.y,
AngleUtil.interpolateShortest(getDirZ(), otherPoint.getDirZ(), fraction));
}
/**
* Return a new DirectedPoint with an in-place rotation around the z-axis by the provided delta. The resulting rotation will
* be normalized between -π and π.
* @param rotateZ double; the rotation around the z-axis
* @return DirectedPoint; a new point with the same coordinates and applied rotation
* @throws IllegalArgumentException when deltaRotZ is NaN
*/
public DirectedPoint2d rotate(final double rotateZ) throws IllegalArgumentException
{
Throw.when(Double.isNaN(rotateZ), IllegalArgumentException.class, "deltaDirZ must be a number (not NaN)");
return new DirectedPoint2d(getX(), getY(), AngleUtil.normalizeAroundZero(getDirZ() + rotateZ));
}
/** {@inheritDoc} */
@Override
public double getDirZ()
{
return this.dirZ;
}
/** {@inheritDoc} */
@Override
public Iterator extends DirectedPoint2d> getPoints()
{
return Arrays.stream(new DirectedPoint2d[] {this}).iterator();
}
/** {@inheritDoc} */
@Override
public String toString()
{
return String.format("[(%f,%f), rot=%f]", getX(), getY(), getDirZ());
}
/** {@inheritDoc} */
@Override
public String toString(final int fractionDigits)
{
int digits = fractionDigits < 0 ? 0 : fractionDigits;
String format = String.format("[(%%.%1$df,%%.%1$df), rot=%%.%1$df]", digits);
return String.format(format, getX(), getY(), getDirZ());
}
/**
* Compare this DirectedPoint2d with another DirectedPoint2d and return true of each of the coordinates is less than
* epsilonCoordinate apart, and the direction components are (normalized) less that epsilonRotation apart.
* @param other DirectedPoint2d; the point to compare with
* @param epsilonCoordinate double; the upper bound of difference for one of the coordinates
* @param epsilonRotation double; the upper bound of difference for one of the rotations
* @return boolean; true if x, y, and z are less than epsilonCoordinate apart, and rotX, rotY and rotZ are less than
* epsilonRotation apart, otherwise false
* @throws NullPointerException when point is null
* @throws IllegalArgumentException epsilonCoordinate or epsilonRotation is NaN
*/
public boolean epsilonEquals(final DirectedPoint2d other, final double epsilonCoordinate, final double epsilonRotation)
{
Throw.whenNull(other, "other point cannot be null");
if (Math.abs(getX() - other.x) > epsilonCoordinate)
{
return false;
}
if (Math.abs(getY() - other.y) > epsilonCoordinate)
{
return false;
}
if (Math.abs(AngleUtil.normalizeAroundZero(getDirZ() - other.getDirZ())) > epsilonRotation)
{
return false;
}
return true;
}
/** {@inheritDoc} */
@Override
public int hashCode()
{
final int prime = 31;
int result = super.hashCode();
long temp;
temp = Double.doubleToLongBits(this.dirZ);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("checkstyle:needbraces")
public boolean equals(final Object obj)
{
if (this == obj)
return true;
if (!super.equals(obj))
return false;
DirectedPoint2d other = (DirectedPoint2d) obj;
if (Double.doubleToLongBits(this.dirZ) != Double.doubleToLongBits(other.dirZ))
return false;
return true;
}
}