Triad.java
/*
* Copyright (C) 2020 Alberto Irurueta Carro (alberto@irurueta.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.irurueta.navigation.inertial.calibration;
import com.irurueta.algebra.Matrix;
import com.irurueta.algebra.WrongSizeException;
import com.irurueta.units.Measurement;
import java.io.Serializable;
import java.util.Objects;
/**
* Contains a triad of measurement data.
*
* @param <U> type of unit.
* @param <M> a type of measurement.
*/
public abstract class Triad<U extends Enum<?>, M extends Measurement<U>, T extends Triad<U, M, T>>
implements Serializable {
/**
* Number of components of measurements.
*/
public static final int COMPONENTS = 3;
/**
* Contains x coordinate of measurement value.
*/
private double valueX;
/**
* Contains y coordinate of measurement value.
*/
private double valueY;
/**
* Contains z coordinate of measurement value.
*/
private double valueZ;
/**
* Contains unit of measurement.
*/
private U unit;
/**
* Constructor.
*
* @param unit unit of measurement.
* @throws IllegalArgumentException if provided unit is null.
*/
protected Triad(final U unit) {
if (unit == null) {
throw new IllegalArgumentException();
}
this.unit = unit;
}
/**
* Constructor.
*
* @param unit unit of measurement.
* @param valueX value of x-coordinate.
* @param valueY value of y-coordinate.
* @param valueZ value of z-coordinate.
* @throws IllegalArgumentException if provided unit is null.
*/
protected Triad(final U unit, final double valueX, final double valueY, final double valueZ) {
this(unit);
setValueCoordinates(valueX, valueY, valueZ);
}
/**
* Copy constructor.
*
* @param other instance to copy from.
*/
protected Triad(final Triad<U, M, T> other) {
copyFrom(other);
}
/**
* Gets x coordinate of measurement value expressed in current unit.
*
* @return x coordinate of measurement value.
*/
public double getValueX() {
return valueX;
}
/**
* Sets x coordinate of measurement value using current unit.
*
* @param valueX x coordinate of measurement value.
*/
public void setValueX(final double valueX) {
this.valueX = valueX;
}
/**
* Gets y coordinate of measurement value expressed in current unit.
*
* @return y coordinate of measurement value.
*/
public double getValueY() {
return valueY;
}
/**
* Sets y coordinate of measurement value using current unit.
*
* @param valueY y coordinate of measurement value.
*/
public void setValueY(final double valueY) {
this.valueY = valueY;
}
/**
* Gets z coordinate of measurement value expressed in current unit.
*
* @return z coordinate of measurement value.
*/
public double getValueZ() {
return valueZ;
}
/**
* Sets z coordinate of measurement value using current unit.
*
* @param valueZ z coordinate of measurement value.
*/
public void setValueZ(final double valueZ) {
this.valueZ = valueZ;
}
/**
* Sets coordinates of measurement using current unit.
*
* @param valueX x coordinate of measurement.
* @param valueY y coordinate of measurement.
* @param valueZ z coordinate of measurement.
*/
public void setValueCoordinates(final double valueX, final double valueY, final double valueZ) {
this.valueX = valueX;
this.valueY = valueY;
this.valueZ = valueZ;
}
/**
* Gets unit of measurement.
*
* @return unit of measurement.
*/
public U getUnit() {
return unit;
}
/**
* Sets unit of measurement.
*
* @param unit unit of measurement.
* @throws IllegalArgumentException if provided value is null.
*/
public void setUnit(final U unit) {
if (unit == null) {
throw new IllegalArgumentException();
}
this.unit = unit;
}
/**
* Sets value coordinates and unit.
*
* @param valueX x coordinate of measurement.
* @param valueY y coordinate of measurement.
* @param valueZ z coordinate of measurement.
* @param unit unit of measurement.
* @throws IllegalArgumentException if provided unit is null.
*/
public void setValueCoordinatesAndUnit(
final double valueX, final double valueY, final double valueZ, final U unit) {
setValueCoordinates(valueX, valueY, valueZ);
setUnit(unit);
}
/**
* Gets measurement values as an array expressed in current unit.
*
* @return array containing measurement values.
*/
public double[] getValuesAsArray() {
return new double[]{valueX, valueY, valueZ};
}
/**
* Gets measurement values as an array expressed in current unit.
*
* @param result instance where result will be stored.
* @throws IllegalArgumentException if provided array does not have
* length 3.
*/
public void getValuesAsArray(final double[] result) {
if (result.length != COMPONENTS) {
throw new IllegalArgumentException();
}
result[0] = valueX;
result[1] = valueY;
result[2] = valueZ;
}
/**
* Sets measurement coordinates from provided array.
*
* @param values array to set values from.
* @throws IllegalArgumentException if provided array does not have
* length 3.
*/
public void setValueCoordinates(final double[] values) {
if (values.length != COMPONENTS) {
throw new IllegalArgumentException();
}
valueX = values[0];
valueY = values[1];
valueZ = values[2];
}
/**
* Gets measurement values as a column matrix expressed in current unit.
*
* @return matrix containing measurement values.
*/
public Matrix getValuesAsMatrix() {
Matrix result = null;
try {
result = new Matrix(COMPONENTS, 1);
getValuesAsMatrix(result);
} catch (final WrongSizeException ignore) {
// never happens
}
return result;
}
/**
* Gets measurement values as a column matrix expressed in current unit.
*
* @param result instance where result will be stored.
* @throws IllegalArgumentException if provided matrix is not 3x1.
*/
public void getValuesAsMatrix(final Matrix result) {
if (result.getRows() != COMPONENTS || result.getColumns() != 1) {
throw new IllegalArgumentException();
}
result.setElementAtIndex(0, valueX);
result.setElementAtIndex(1, valueY);
result.setElementAtIndex(2, valueZ);
}
/**
* Sets measurement coordinates from provided column matrix.
*
* @param values matrix to set values from.
* @throws IllegalArgumentException if provided matrix is not 3x1.
*/
public void setValueCoordinates(final Matrix values) {
if (values.getRows() != COMPONENTS || values.getColumns() != 1) {
throw new IllegalArgumentException();
}
valueX = values.getElementAtIndex(0);
valueY = values.getElementAtIndex(1);
valueZ = values.getElementAtIndex(2);
}
/**
* Gets x coordinate of measurement value.
*
* @return x coordinate of measurement value.
*/
public abstract M getMeasurementX();
/**
* Gets x coordinate of measurement value.
*
* @param result instance where x coordinate of measurement value
* will be stored.
*/
public abstract void getMeasurementX(final M result);
/**
* Sets x coordinate of measurement value.
*
* @param measurementX x coordinate of measurement value.
*/
public abstract void setMeasurementX(final M measurementX);
/**
* Gets y coordinate of measurement value.
*
* @return y coordinate of measurement value.
*/
public abstract M getMeasurementY();
/**
* Gets y coordinate of measurement value.
*
* @param result instance where y coordinate of measurement value
* will be stored.
*/
public abstract void getMeasurementY(final M result);
/**
* Sets y coordinate of measurement value.
*
* @param measurementY y coordinate of measurement value.
*/
public abstract void setMeasurementY(final M measurementY);
/**
* Gets z coordinate of measurement value.
*
* @return z coordinate of measurement value.
*/
public abstract M getMeasurementZ();
/**
* Gets z coordinate of measurement value.
*
* @param result instance where z coordinate of measurement value
* will be stored.
*/
public abstract void getMeasurementZ(final M result);
/**
* Sets z coordinate of measurement value.
*
* @param measurementZ z coordinate of measurement value.
*/
public abstract void setMeasurementZ(final M measurementZ);
/**
* Sets measurement coordinates.
*
* @param measurementX x coordinate of measurement value.
* @param measurementY y coordinate of measurement value.
* @param measurementZ z coordinate of measurement value.
*/
public abstract void setMeasurementCoordinates(
final M measurementX, final M measurementY, final M measurementZ);
/**
* Gets squared norm expressed in squared current unit.
*
* @return squared norm for triad values.
*/
public double getSqrNorm() {
return valueX * valueX + valueY * valueY + valueZ * valueZ;
}
/**
* Gets norm expressed in current unit.
*
* @return norm for triad values.
*/
public double getNorm() {
return Math.sqrt(getSqrNorm());
}
/**
* Gets norm as a measurement.
*
* @return norm as a measurement.
*/
public abstract M getMeasurementNorm();
/**
* Gets norm as a measurement.
*
* @param result instance where norm value will be stored.
*/
public void getMeasurementNorm(final M result) {
result.setValue(getNorm());
result.setUnit(getUnit());
}
/**
* Copies this instance data into provided instance.
*
* @param output destination instance where data will be copied to.
*/
public void copyTo(final Triad<U, M, T> output) {
output.copyFrom(this);
}
/**
* Copies data of provided instance into this instance.
*
* @param input instance to copy data from.
*/
public void copyFrom(final Triad<U, M, T> input) {
valueX = input.valueX;
valueY = input.valueY;
valueZ = input.valueZ;
unit = input.unit;
}
/**
* Creates and returns a new instance having exactly the same contents
* as this instance.
*
* @return a copy of this instance.
*/
public abstract T copy();
/**
* Computes and returns hash code for this instance. Hash codes are almost unique
* values that are useful for fas classification and storage of objects in collections.
*
* @return Hash code.
*/
@Override
public int hashCode() {
return Objects.hash(valueX, valueY, valueZ, unit);
}
/**
* Checks if provided instance has exactly the same contents as this instance.
*
* @param other instance to be compared.
* @return true if both instances are considered to be equal, false otherwise.
*/
public boolean equals(final Triad<U, M, T> other) {
return equals(other, 0.0);
}
/**
* Checks if provided instance has contents similar to this instance up to provided
* threshold value.
*
* @param other instance to be compared.
* @param threshold maximum allowed difference between values.
* @return true if both instances are considered to be equal (up to provided
* threshold), false otherwise.
*/
public boolean equals(final Triad<U, M, T> other, final double threshold) {
if (other == null) {
return false;
}
return Math.abs(valueX - other.valueX) <= threshold && Math.abs(valueY - other.valueY) <= threshold
&& Math.abs(valueZ - other.valueZ) <= threshold && Objects.equals(unit, other.unit);
}
/**
* Checks if provided object is a Triad instance having exactly the same contents
* as this instance.
*
* @param o object to be compared.
* @return true if both objects are considered to be equal, false otherwise.
*/
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
//noinspection unchecked
final var triad = (Triad<U, M, T>) o;
return equals(triad);
}
}