AffineParameters3D.java
/*
* Copyright (C) 2012 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.geometry;
import com.irurueta.algebra.Matrix;
import com.irurueta.algebra.WrongSizeException;
import java.io.Serializable;
/**
* This class defines additional parameters that can be defined on affine
* 3D transformations.
*/
public class AffineParameters3D implements Serializable {
/**
* Default scale value having no effect on transformations.
*/
public static final double DEFAULT_SCALE = 1.0;
/**
* Default skewness value having no effect on transformations.
*/
public static final double DEFAULT_SKEWNESS = 0.0;
/**
* Number of inhomogeneous coordinates in 3D space.
*/
public static final int INHOM_COORDS = 3;
/**
* Default threshold to determine whether a matrix is a valid 3x3 upper
* triangular one.
*/
private static final double DEFAULT_VALID_THRESHOLD = 1e-8;
/**
* Scale on x coordinates.
*/
private double scaleX;
/**
* Scale on y coordinates.
*/
private double scaleY;
/**
* Scale on z coordinates.
*/
private double scaleZ;
/**
* Skewness factor between axes x-y. If 0.0, x and y axes remain orthogonal,
* otherwise they get slanted.
*/
private double skewnessXY;
/**
* Skewness factor between axes x-z. If 0.0, x and z axes remain orthogonal,
* otherwise they get slanted.
*/
private double skewnessXZ;
/**
* Skewness factor between axes y-z. If 0.0, y and z axes remain orthogonal,
* otherwise they get slanted.
*/
private double skewnessYZ;
/**
* Constructor.
* Sets default scale and skewness.
*/
public AffineParameters3D() {
scaleX = scaleY = scaleZ = DEFAULT_SCALE;
skewnessXY = skewnessXZ = skewnessYZ = DEFAULT_SKEWNESS;
}
/**
* Constructor with scale.
* Sets default skewness and provided scale.
*
* @param scale Scale to be set (in x, y and z axes). A value between 0.0
* and 1.0 will reduce objects size, a value larger than 1.0 will enlarge
* objects size, and negative values will reverse objects.
*/
public AffineParameters3D(final double scale) {
scaleX = scaleY = scaleZ = scale;
skewnessXY = skewnessXZ = skewnessYZ = DEFAULT_SKEWNESS;
}
/**
* Constructor with scale and skewness.
*
* @param scale Scale to be set (in x, y and z axes). A value between 0.0
* and 1.0 will reduce objects size, a value larger than 1.0 will enlarge
* objects size, and negative values will reverse objects.
* @param skewness Skewness to be set for all axes.
*/
public AffineParameters3D(final double scale, final double skewness) {
scaleX = scaleY = scaleZ = scale;
skewnessXY = skewnessXZ = skewnessYZ = skewness;
}
/**
* Constructor with scale and skewness on each axis.
*
* @param scaleX Scale to be set on x-axis. A value between 0.0 and 1.0
* will reduce objects size, a value larger than 1.0 will enlarge objects
* size, and negative values will reverse objects.
* @param scaleY Scale to be set on y-axis. A value between 0.0 and 1.0
* will reduce objects size, a value larger than 1.0 will enlarge objects.
* @param scaleZ Scale to be set on z-axis. A value between 0.0 and 1.0
* will reduce objects size, a value larger than 1.0 will enlarge objects.
* @param skewnessXY Skewness to be set for axes x-y.
* @param skewnessXZ Skewness to be set for axes x-z.
* @param skewnessYZ Skewness to be set for axes y-z.
*/
public AffineParameters3D(final double scaleX, final double scaleY, final double scaleZ,
final double skewnessXY, final double skewnessXZ, final double skewnessYZ) {
this.scaleX = scaleX;
this.scaleY = scaleY;
this.scaleZ = scaleZ;
this.skewnessXY = skewnessXY;
this.skewnessXZ = skewnessXZ;
this.skewnessYZ = skewnessYZ;
}
/**
* Constructor with matrix and threshold.
*
* @param m Upper triangular matrix to extract affine parameters from.
* @param threshold Threshold to determine whether provided matrix is a
* valid upper triangular one.
* @throws IllegalArgumentException Raised if provided matrix is not 3x3 or
* if it is not upper triangular, or if threshold is negative.
*/
public AffineParameters3D(final Matrix m, final double threshold) {
fromMatrix(m, threshold);
}
/**
* Constructor with matrix.
*
* @param m Upper triangular matrix to extract affine parameters from.
* @throws IllegalArgumentException Raised if provided matrix is not 3x3 or
* if it is not upper triangular, or if threshold is negative.
*/
public AffineParameters3D(final Matrix m) {
fromMatrix(m);
}
/**
* Returns scale for x-axis.
* A value between 0.0 and 1.0 will reduce objects size, a value larger than
* 1.0 will enlarge objects size, and negative values will reverse objects.
*
* @return Scale for x axis.
*/
public double getScaleX() {
return scaleX;
}
/**
* Sets scale for x-axis.
* A value between 0.0 and 1.0 will reduce objects size, a value larger than
* 1.0 will enlarge objects size, and negative values will reverse objects.
*
* @param scaleX scale to be set on x-axis.
*/
public void setScaleX(final double scaleX) {
this.scaleX = scaleX;
}
/**
* Returns scale for y-axis.
* A value between 0.0 and 1.0 will reduce objects size, a value larger than
* 1.0 will enlarge objects size, and negative values will reverse objects.
*
* @return Scale for y axis.
*/
public double getScaleY() {
return scaleY;
}
/**
* Sets scale for y-axis.
* A value between 0.0 and 1.0 will reduce objects size, a value larger than
* 1.0 will enlarge objects size, and negative values will reverse objects.
*
* @param scaleY scale to be set on y-axis.
*/
public void setScaleY(final double scaleY) {
this.scaleY = scaleY;
}
/**
* Returns scale for z axis.
* A value between 0.0 and 1.0 will reduce objects size, a value larger than
* 1.0 will enlarge objects size, and negative values will reverse objects.
*
* @return Scale for z axis.
*/
public double getScaleZ() {
return scaleZ;
}
/**
* Sets scale for z axis.
* A value between 0.0 and 1.0 will reduce objects size, a value larger than
* 1.0 will enlarge objects size, and negative values will reverse objects.
*
* @param scaleZ scale to be set on z axis.
*/
public void setScaleZ(final double scaleZ) {
this.scaleZ = scaleZ;
}
/**
* Sets overall scale (for x, y and z axes).
* A value between 0.0 and 1.0 will reduce objects size, a value larger than
* 1.0 will enlarge objects size, and negative values will reverse objects.
*
* @param scale Scale to be set for x, y and z axes.
*/
public void setScale(final double scale) {
scaleX = scaleY = scaleZ = scale;
}
/**
* Returns skewness value for x-y axes.
* A value of 0.0 indicates that horizontal and vertical axis are
* orthogonal, otherwise they are slanted to each other.
*
* @return Skewness value for x-y axes.
*/
public double getSkewnessXY() {
return skewnessXY;
}
/**
* Sets skewness value for x-y axes.
* A value of 0.0 indicates that horizontal and vertical axis are
* orthogonal, otherwise they are slanted to each other.
*
* @param skewnessXY Skewness to be set for x-y axes.
*/
public void setSkewnessXY(final double skewnessXY) {
this.skewnessXY = skewnessXY;
}
/**
* Returns skewness value for x-z axes.
* A value of 0.0 indicates that horizontal and vertical axis are
* orthogonal, otherwise they are slanted to each other.
*
* @return Skewness value for x-z axes.
*/
public double getSkewnessXZ() {
return skewnessXZ;
}
/**
* Sets skewness value for x-z axes.
* A value of 0.0 indicates that horizontal and vertical axis are
* orthogonal, otherwise they are slanted to each other.
*
* @param skewnessXZ Skewness to be set for x-z axes.
*/
public void setSkewnessXZ(final double skewnessXZ) {
this.skewnessXZ = skewnessXZ;
}
/**
* Returns skewness value for y-z axes.
* A value of 0.0 indicates that horizontal and vertical axis are
* orthogonal, otherwise they are slanted to each other.
*
* @return Skewness value for y-z axes.
*/
public double getSkewnessYZ() {
return skewnessYZ;
}
/**
* Sets skewness value for y-z axes.
* A value of 0.0 indicates that horizontal and vertical axis are
* orthogonal, otherwise they are slanted to each other.
*
* @param skewnessYZ Skewness to be set for y-z axes.
*/
public void setSkewnessYZ(final double skewnessYZ) {
this.skewnessYZ = skewnessYZ;
}
/**
* Converts this affine parameters instance into matrix representation
*
* @return A matrix representation of this instance.
*/
public Matrix asMatrix() {
Matrix m = null;
try {
m = new Matrix(INHOM_COORDS, INHOM_COORDS);
asMatrix(m);
} catch (final WrongSizeException ignore) {
// never happens
}
return m;
}
/**
* Converts this affine parameters instance into matrix representation and
* stores the result into provided matrix.
*
* @param m Matrix where representation of this instance will be stored.
* @throws IllegalArgumentException Raised if provided matrix is not 3x3.
*/
public void asMatrix(final Matrix m) {
if (m.getRows() != INHOM_COORDS || m.getColumns() != INHOM_COORDS) {
throw new IllegalArgumentException();
}
m.setElementAt(0, 0, scaleX);
m.setElementAt(1, 0, 0.0);
m.setElementAt(2, 0, 0.0);
m.setElementAt(0, 1, skewnessXY);
m.setElementAt(1, 1, scaleY);
m.setElementAt(2, 1, 0.0);
m.setElementAt(0, 2, skewnessXZ);
m.setElementAt(1, 2, skewnessYZ);
m.setElementAt(2, 2, scaleZ);
}
/**
* Sets parameters of this instance from provided matrix.
*
* @param m Matrix to set parameters from. Provided matrix must be 3x3 and
* upper triangular.
* @throws IllegalArgumentException Raised if provided matrix is not 3x3 or
* if it is not upper triangular.
*/
public final void fromMatrix(final Matrix m) {
fromMatrix(m, DEFAULT_VALID_THRESHOLD);
}
/**
* Sets parameters of this instance from provided matrix.
*
* @param m Matrix to set parameters from. Provided matrix must be 3x3 and
* upper triangular up to provided threshold.
* @param threshold Threshold to determine whether provided matrix is upper
* triangular. Matrix will be considered upper triangular if its lower
* triangular elements are smaller or equal than provided threshold.
* @throws IllegalArgumentException Raised if provided matrix is not 3x3 or
* if it is not upper triangular or if threshold is negative.
*/
public final void fromMatrix(final Matrix m, final double threshold) {
if (!isValidMatrix(m, threshold)) {
throw new IllegalArgumentException();
}
scaleX = m.getElementAt(0, 0);
skewnessXY = m.getElementAt(0, 1);
scaleY = m.getElementAt(1, 1);
skewnessXZ = m.getElementAt(0, 2);
skewnessYZ = m.getElementAt(1, 2);
scaleZ = m.getElementAt(2, 2);
}
/**
* Returns boolean indicating whether provided matrix is a valid matrix
* to set affine parameters from.
* Valid matrices need to be 3x3 and upper triangular.
*
* @param m A matrix to determine whether it is valid to set affine
* parameters from.
* @return True if matrix is valid, false otherwise.
*/
public static boolean isValidMatrix(final Matrix m) {
return isValidMatrix(m, DEFAULT_VALID_THRESHOLD);
}
/**
* Returns boolean indicating whether provided matrix is a valid matrix to
* set affine parameters form.
* Valid matrices need to be 3x3 and upper triangular up to provided
* threshold. In Layman terms, a valid matrix lower triangular elements need
* to be smaller or equal than provided threshold.
*
* @param m A matrix to determine whether it is valid to set affine
* parameters from.
* @param threshold A threshold to determine whether provided matrix is
* upper triangular. Matrix will be considered upper triangular if its lower
* triangular elements are smaller or equal than provided threshold (without
* taking into account the sign of the elements).
* @return True if matrix is valid, false otherwise.
* @throws IllegalArgumentException Raised if provided threshold is negative.
*/
@SuppressWarnings("DuplicatedCode")
public static boolean isValidMatrix(final Matrix m, final double threshold) {
if (threshold < 0.0) {
throw new IllegalArgumentException();
}
if (m.getRows() != INHOM_COORDS || m.getColumns() != INHOM_COORDS) {
return false;
}
// check is upper triangular
final var rows = m.getRows();
final var cols = m.getColumns();
for (var v = 0; v < cols; v++) {
for (var u = 0; u < rows; u++) {
if (u > v && Math.abs(m.getElementAt(u, v)) > threshold) {
return false;
}
}
}
return true;
}
}