net.algart.math.geometry.StraightLine3D Maven / Gradle / Ivy
Show all versions of algart Show documentation
package net.algart.math.geometry;
import java.util.Objects;
import java.util.random.RandomGenerator;
/**
* Directional infinite straight line in 3D space.
* It is defined as some start point o=(x0,y0,z0), belonging to this straight,
* and some direction, represented as a unit vector d=(dx,dy,dz).
* The line consists of all point p=o+td, −∞<t<+∞.
*
* This class is not thread-safe, but is thread-compatible
* and can be synchronized manually if multithreading access is necessary.
*/
public final class StraightLine3D implements Cloneable {
private double x0 = 0.0;
private double y0 = 0.0;
private double z0 = 0.0;
private double dx = 1.0;
private double dy = 0.0;
private double dz = 0.0;
private StraightLine3D() {
}
/**
* Creates some new straight line, passing through the origin (0,0,0).
* The direction of this straight is (1,0,0) (x-axis), but you should not use this fact:
* in future versions this may change.
*
* @return new straight line.
*/
public static StraightLine3D newLine() {
return new StraightLine3D();
}
/**
* Creates new straight line, passing through the origin (0,0,0), with the given direction.
*
* If the given d vector is not unit, it is automatically
* replaced with a unit vector of the same direction: all components are divided by its length.
* But if the vector is shorter than {@link Orthonormal3DBasis#MIN_ALLOWED_LENGTH},
* an exception is thrown.
*
* @param dx x-component of the direction d.
* @param dy y-component of the direction d.
* @param dz z-component of the direction d.
* @return new straight line.
* @throws IllegalArgumentException if the specified vector is zero or extremely short.
*/
public static StraightLine3D newLineThroughOrigin(
double dx, double dy, double dz) {
return new StraightLine3D().setDirection(dx, dy, dz);
}
/**
* Creates new straight line, passing through the given start point (x0,y0,z0)
, with the given direction.
*
*
If the given d vector is not unit, it is automatically
* replaced with a unit vector of the same direction: all components are divided by its length.
* But if the vector is shorter than {@link Orthonormal3DBasis#MIN_ALLOWED_LENGTH},
* an exception is thrown.
*
* @param x0 x-coordinate of the start point o.
* @param y0 y-coordinate of the start point o.
* @param z0 z-coordinate of the start point o.
* @param dx x-component of the direction d.
* @param dy y-component of the direction d.
* @param dz z-component of the direction d.
* @return new straight line.
* @throws IllegalArgumentException if the specified vector is zero or extremely short.
*/
public static StraightLine3D newLine(
double x0, double y0, double z0,
double dx, double dy, double dz) {
return new StraightLine3D().setStart(x0, y0, z0).setDirection(dx, dy, dz);
}
/**
* Creates new straight line, passing through the given start point (x0,y0,z0)
* and directed along the unit vector i of the specified basis.
*
* @param x0 x-coordinate of the start point o.
* @param y0 y-coordinate of the start point o.
* @param z0 z-coordinate of the start point o.
* @param basis some orthonormal basis (i, j, k).
* @return new straight line.
* @throws NullPointerException if basis
is {@code null}.
*/
public static StraightLine3D newLineAlongI(double x0, double y0, double z0, Orthonormal3DBasis basis) {
return new StraightLine3D().setStart(x0, y0, z0).setDirectionAlongI(basis);
}
/**
* Creates new straight line, passing through the given start point (x0,y0,z0)
* and directed along the unit vector j of the specified basis.
*
* @param x0 x-coordinate of the start point o.
* @param y0 y-coordinate of the start point o.
* @param z0 z-coordinate of the start point o.
* @param basis some orthonormal basis (i, j, k).
* @return new straight line.
* @throws NullPointerException if basis
is {@code null}.
*/
public static StraightLine3D newLineAlongJ(double x0, double y0, double z0, Orthonormal3DBasis basis) {
return new StraightLine3D().setStart(x0, y0, z0).setDirectionAlongJ(basis);
}
/**
* Creates new straight line, passing through the given start point (x0,y0,z0)
* and directed along the unit vector k of the specified basis.
*
* @param x0 x-coordinate of the start point o.
* @param y0 y-coordinate of the start point o.
* @param z0 z-coordinate of the start point o.
* @param basis some orthonormal basis (i, j, k).
* @return new straight line.
* @throws NullPointerException if basis
is {@code null}.
*/
public static StraightLine3D newLineAlongK(double x0, double y0, double z0, Orthonormal3DBasis basis) {
return new StraightLine3D().setStart(x0, y0, z0).setDirectionAlongK(basis);
}
/**
* Returns x-coordinate of the start point o.
*
* @return x-coordinate of the start point o.
*/
public double x0() {
return x0;
}
/**
* Sets x-coordinate of the start point o.
*
* @param x0 new x-coordinate of the start point o.
* @return a reference to this object.
*/
public StraightLine3D x0(double x0) {
this.x0 = x0;
return this;
}
/**
* Returns y-coordinate of the start point o.
*
* @return y-coordinate of the start point o.
*/
public double y0() {
return y0;
}
/**
* Sets y-coordinate of the start point o.
*
* @param y0 new y-coordinate of the start point o.
* @return a reference to this object.
*/
public StraightLine3D y0(double y0) {
this.y0 = y0;
return this;
}
/**
* Returns z-coordinate of the start point o.
*
* @return z-coordinate of the start point o.
*/
public double z0() {
return z0;
}
/**
* Sets z-coordinate of the start point o.
*
* @param z0 new z-coordinate of the start point o.
* @return a reference to this object.
*/
public StraightLine3D z0(double z0) {
this.z0 = z0;
return this;
}
/**
* Sets new start point o.
*
* @param x0 new x-coordinate of the start point o.
* @param y0 new y-coordinate of the start point o.
* @param z0 new z-coordinate of the start point o.
* @return a reference to this object.
*/
public StraightLine3D setStart(double x0, double y0, double z0) {
this.x0 = x0;
this.y0 = y0;
this.z0 = z0;
return this;
}
/**
* Returns x-component of the direction d.
*
* @return x-component of the direction d.
*/
public double dx() {
return dx;
}
/**
* Returns y-component of the direction d.
*
* @return y-component of the direction d.
*/
public double dy() {
return dy;
}
/**
* Returns z-component of the direction d.
*
* @return z-component of the direction d.
*/
public double dz() {
return dz;
}
/**
* Sets new direction d.
*
*
If the given d vector is not unit, it is automatically
* replaced with a unit vector of the same direction: all components are divided by its length.
* But if the vector is shorter than {@link Orthonormal3DBasis#MIN_ALLOWED_LENGTH},
* an exception is thrown.
*
* @param dx new x-component of the direction d.
* @param dy new y-component of the direction d.
* @param dz new z-component of the direction d.
* @return a reference to this object.
* @throws IllegalArgumentException if the specified vector is zero or extremely short.
*/
public StraightLine3D setDirection(double dx, double dy, double dz) {
final double length = Orthonormal3DBasis.length(dx, dy, dz);
if (length < Orthonormal3DBasis.MIN_ALLOWED_LENGTH) {
throw new IllegalArgumentException("Zero or too short direction vector ("
+ dx + ", " + dy + ", " + dz + ")"
+ " (vectors with length <" + Orthonormal3DBasis.MIN_ALLOWED_LENGTH + " are not allowed)");
}
final double mult = 1.0 / length;
setDirectionComponents(dx * mult, dy * mult, dz * mult);
return this;
}
/**
* Shift the start point o along the direction d:
* o = o + shift * d.
* Please remember that d vector is unit, so the argument is equal to the actual value
* of shifting the start point.
*
* @param shift value of shifting.
* @return a reference to this object.
*/
public StraightLine3D shiftAlong(double shift) {
x0 += shift * dx;
y0 += shift * dy;
z0 += shift * dz;
return this;
}
/**
* Sets new direction d equal to the unit vector i of the specified basis.
*
* @param basis some orthonormal basis (i, j, k).
* @return a reference to this object.
* @throws NullPointerException if basis
is {@code null}.
*/
public StraightLine3D setDirectionAlongI(Orthonormal3DBasis basis) {
Objects.requireNonNull(basis, "Null basis");
return setDirection(basis.ix(), basis.iy(), basis.iz());
}
/**
* Sets new direction d equal to the unit vector j of the specified basis.
*
* @param basis some orthonormal basis (i, j, k).
* @return a reference to this object.
* @throws NullPointerException if basis
is {@code null}.
*/
public StraightLine3D setDirectionAlongJ(Orthonormal3DBasis basis) {
Objects.requireNonNull(basis, "Null basis");
return setDirection(basis.jx(), basis.jy(), basis.jz());
}
/**
* Sets new direction d equal to the unit vector k of the specified basis.
*
* @param basis some orthonormal basis (i, j, k).
* @return a reference to this object.
* @throws NullPointerException if basis
is {@code null}.
*/
public StraightLine3D setDirectionAlongK(Orthonormal3DBasis basis) {
Objects.requireNonNull(basis, "Null basis");
return setDirection(basis.kx(), basis.ky(), basis.kz());
}
/**
* Sets new direction d equal to the unit vector (1,0,0).
*
* @return a reference to this object.
*/
public StraightLine3D setDirectionAlongX() {
return setDirection(1.0, 0.0, 0.0);
}
/**
* Sets new direction d equal to the unit vector (0,1,0).
*
* @return a reference to this object.
*/
public StraightLine3D setDirectionAlongY() {
return setDirection(0.0, 1.0, 0.0);
}
/**
* Sets new direction d equal to the unit vector (0,0,1).
*
* @return a reference to this object.
*/
public StraightLine3D setDirectionAlongZ() {
return setDirection(0.0, 0.0, 1.0);
}
/**
* Sets new direction randomly with uniform distribution in the space.
* This is chosen with help of random.nextDouble()
method.
*
* @param random random generator used to create the basis.
* @return a reference to this object.
*/
public StraightLine3D setRandomDirection(RandomGenerator random) {
for (; ; ) {
final double dx = 2 * random.nextDouble() - 1.0;
final double dy = 2 * random.nextDouble() - 1.0;
final double dz = 2 * random.nextDouble() - 1.0;
final double distanceSqr = dx * dx + dy * dy + dz * dz;
if (distanceSqr >= 0.01 && distanceSqr < 1.0) {
// Note: the second check is necessary to provide uniform distribution in a sphere (not in a cube).
return setDirection(dx, dy, dz);
}
}
}
/**
* Sets this straight to be identical to the passed straight.
*
* @param other other straight.
* @return a reference to this object.
* @throws NullPointerException if the argument is {@code null}.
*/
public StraightLine3D setTo(StraightLine3D other) {
Objects.requireNonNull(other, "Null other");
this.x0 = other.x0;
this.y0 = other.y0;
this.z0 = other.z0;
this.dx = other.dx;
this.dy = other.dy;
this.dz = other.dz;
return this;
}
/**
* Returns {@link #x0() x0} + t * {@link #dx() dx}.
*
* @param t the shift value from the start point.
* @return x-coordinate of a point.
*/
public double x(double t) {
return x0 + t * dx;
}
/**
* Returns {@link #y0() y0} + t * {@link #dy() dy}.
*
* @param t the shift value from the start point.
* @return y-coordinate of a point.
*/
public double y(double t) {
return y0 + t * dy;
}
/**
* Returns {@link #z0() z0} + t * {@link #dz() dz}.
*
* @param t the shift value from the start point.
* @return z-coordinate of a point.
*/
public double z(double t) {
return z0 + t * dz;
}
/**
* Returns projection of the given vector a to this straight: ax * dx + ay * dy + az * dz
.
*
*
Equivalent to
* {@link Orthonormal3DBasis#scalarProduct
* Orthonormal3DBasis.scalarProduct}(ax, ay, ax, dx, dy, dz)
.
*
* @param ax x-component of the vector.
* @param ay y-component of the vector.
* @param az z-component of the vector.
* @return projection of the given vector to the direction of this straight.
*/
public double vectorProjection(double ax, double ay, double az) {
return ax * dx + ay * dy + az * dz;
}
/**
* Returns (x−x0)*dx + (y−y0)*dy + (z−z0)*dz
.
*
* @param x x-coordinate of the point.
* @param y y-coordinate of the point.
* @param z z-coordinate of the point.
* @return t value for the projection of the given point to this straight.
*/
public double pointProjection(double x, double y, double z) {
return (x - x0) * dx + (y - y0) * dy + (z - z0) * dz;
}
/**
* Returns (x−x0)2 + (y−y0)2 + (z−z0)2.
*
* @param x x-coordinate of the point.
* @param y y-coordinate of the point.
* @param z z-coordinate of the point.
* @return square of the distance to the start point o.
*/
public double distanceToStartPointSquare(double x, double y, double z) {
return Orthonormal3DBasis.lengthSquare(x - x0, y - y0, z - z0);
}
/**
* Returns the distance from the given point (x,y,z)
to the start point (x0,y0,z0)
.
* Equivalent to
* Math.sqrt({@link #distanceToStartPointSquare distanceToStartPointSquare}(x, y, z))
.
*
* @param x x-coordinate of the point.
* @param y y-coordinate of the point.
* @param z z-coordinate of the point.
* @return square of the distance to the start point o.
*/
public double distanceToStartPoint(double x, double y, double z) {
return Math.sqrt(distanceToStartPointSquare(x, y, z));
}
/**
* Returns the square of the distance from the given point (x,y,z)
to this straight.
*
* Equivalent to
* {@link StraightLine3D#distanceToStraightSquare(double, double, double, double, double, double)
* StraightLine3D.distanceToStraightSquare}({@link #dx()}, {@link #dy()}, {@link #dz()}, x - {@link
* #x0()}, y - {@link #y0()}, z - {@link #z0()}).
*
* @param x x-coordinate of the point.
* @param y y-coordinate of the point.
* @param z z-coordinate of the point.
* @return square of the distance between the point and this straight.
*/
public double distanceToStraightSquare(double x, double y, double z) {
return distanceToStraightSquare(dx, dy, dz, x - x0, y - y0, z - z0);
}
/**
* Returns the distance from the given point (x,y,z)
to this straight.
* Equivalent to
* Math.sqrt({@link #distanceToStraightSquare(double, double, double)
* distanceToStraightSquare}(x, y, z))
.
*
* @param x x-coordinate of the point.
* @param y y-coordinate of the point.
* @param z z-coordinate of the point.
* @return distance between the point and this straight.
*/
public double distanceToStraight(double x, double y, double z) {
return Math.sqrt(distanceToStraightSquare(x, y, z));
}
/**
* Returns a brief string description of this object.
*
* The result of this method may depend on implementation.
*
* @return a brief string description of this object.
*/
public String toString() {
return "straight (" + x0 + "," + y0 + "," + z0 + ")+t*(" + dx + "," + dy + "," + dz + ")";
}
/**
* Indicates whether some other object is an instance of this class, containing the same straight line
* (the same o and d).
* The corresponding coordinates are compared as in Double.equals
method,
* i.e. they are converted to long
values by Double.doubleToLongBits
method
* and the results are compared.
*
* @param o the object to be compared for equality with this instance.
* @return true
if and only if the specified object is an instance of {@link StraightLine3D},
* representing the same straight line as this object.
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof StraightLine3D that)) {
return false;
}
return (Double.doubleToLongBits(that.x0) == Double.doubleToLongBits(x0)
&& Double.doubleToLongBits(that.y0) == Double.doubleToLongBits(y0)
&& Double.doubleToLongBits(that.z0) == Double.doubleToLongBits(z0)
&& Double.doubleToLongBits(that.dx) == Double.doubleToLongBits(dx)
&& Double.doubleToLongBits(that.dy) == Double.doubleToLongBits(dy)
&& Double.doubleToLongBits(that.dz) == Double.doubleToLongBits(dz));
}
/**
* Returns the hash code of this object.
*
* @return the hash code of this object.
*/
@Override
public int hashCode() {
int result = 0;
result = 37 * result + Double.hashCode(x0);
result = 37 * result + Double.hashCode(y0);
result = 37 * result + Double.hashCode(z0);
result = 37 * result + Double.hashCode(dx);
result = 37 * result + Double.hashCode(dy);
result = 37 * result + Double.hashCode(dz);
return result;
}
/**
* Returns an exact copy of this object.
*
* @return a reference to the clone.
*/
@Override
public StraightLine3D clone() {
try {
return (StraightLine3D) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
/**
* Returns the square of the distance from the given point (x,y,z)
to the straight
* {@link #newLineThroughOrigin(double, double, double) getInstanceFromOrigin}(dx, dy, dz)
,
* where d=(dx,dy,dz)
is some unit vector.
*
*
This method works faster than creating a new instance of this class and calling its
* {@link #distanceToStraightSquare(double, double, double)} method.
* But this method requires that the vector (dx, dy, dz)
to be unit:
* dx * dx + dy * dy+ dz * dz = 1.0
,
* otherwise its result will be incorrect.
*
* @param dx x-component of the unit direction vector d.
* @param dy y-component of the unit direction vector d.
* @param dz z-component of the unit direction vector d.
* @param x x-coordinate of the point.
* @param y y-coordinate of the point.
* @param z z-coordinate of the point.
*/
public static double distanceToStraightSquare(double dx, double dy, double dz, double x, double y, double z) {
final double t = x * dx + y * dy + z * dz;
return Orthonormal3DBasis.lengthSquare(x - t * dx, y - t * dy, z - t * dz);
// - more stable solution than x^2+y^2+z^2-t^2
}
/**
* Returns the distance from the given point (x,y,z)
to the straight
* {@link #newLineThroughOrigin(double, double, double) getInstanceFromOrigin}(dx, dy, dz)
,
* where d=(dx,dy,dz)
is some unit vector.
*
*
Equivalent to
* Math.sqrt({@link #distanceToStraightSquare(double, double, double, double, double, double)
* distanceToStraightSquare}(dx, dy, dz, x, y, z))
.
*
* @param dx x-component of the unit direction vector d.
* @param dy y-component of the unit direction vector d.
* @param dz z-component of the unit direction vector d.
* @param x x-coordinate of the point.
* @param y y-coordinate of the point.
* @param z z-coordinate of the point.
*/
public static double distanceToStraight(double dx, double dy, double dz, double x, double y, double z) {
return Math.sqrt(distanceToStraightSquare(dx, dy, dz, x, y, z));
}
// Called via reflection in the test for debugging needs; must be private
private void setDirectionComponents(double dx, double dy, double dz) {
this.dx = dx;
this.dy = dy;
this.dz = dz;
}
}