1 /*
2 * Copyright (C) 2018 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.irurueta.geometry;
18
19 import com.irurueta.algebra.AlgebraException;
20 import com.irurueta.algebra.ArrayUtils;
21 import com.irurueta.algebra.Matrix;
22 import com.irurueta.algebra.NonSymmetricPositiveDefiniteMatrixException;
23
24 /**
25 * Contains methods to convert covariance matrices into ellipsoids representing accuracy
26 * with requested confidence.
27 */
28 public class Accuracy3D extends Accuracy {
29
30 /**
31 * Constructor.
32 */
33 public Accuracy3D() {
34 super();
35 }
36
37 /**
38 * Constructor.
39 *
40 * @param covarianceMatrix covariance matrix to be set. Must be 3x3 and positive
41 * definite.
42 * @throws IllegalArgumentException if provided matrix is not square (it must also be
43 * positive definite to be properly converted to an ellipsoid).
44 * @throws NonSymmetricPositiveDefiniteMatrixException if provided matrix is not symmetric and
45 * positive definite.
46 */
47 public Accuracy3D(final Matrix covarianceMatrix) throws NonSymmetricPositiveDefiniteMatrixException {
48 super(covarianceMatrix);
49 }
50
51 /**
52 * Constructor.
53 *
54 * @param confidence confidence of provided accuracy of an estimated position.
55 * @throws IllegalArgumentException if provided value is not within 0 and 1.
56 */
57 public Accuracy3D(final double confidence) {
58 super(confidence);
59 }
60
61 /**
62 * Constructor.
63 *
64 * @param covarianceMatrix covariance matrix to be set. Must be 3x3 and positive
65 * definite.
66 * @param confidence confidence of provided accuracy of an estimated position.
67 * @throws IllegalArgumentException if provided matrix is not square (it must also be
68 * positive definite to be properly converted to an ellipsoid),
69 * or if provided confidence value is not within 0 and 1.
70 * @throws NonSymmetricPositiveDefiniteMatrixException if provided matrix is not symmetric and
71 * positive definite.
72 */
73 public Accuracy3D(final Matrix covarianceMatrix, final double confidence)
74 throws NonSymmetricPositiveDefiniteMatrixException {
75 super(covarianceMatrix, confidence);
76 }
77
78 /**
79 * Gets number of dimensions.
80 *
81 * @return always returns 3.
82 */
83 @Override
84 public int getNumberOfDimensions() {
85 return Point3D.POINT3D_INHOMOGENEOUS_COORDINATES_LENGTH;
86 }
87
88 /**
89 * Converts provided covariance matrix into a 3D ellipsoid taking into account current
90 * confidence and standard deviation factor.
91 *
92 * @return ellipsoid representing accuracy of covariance matrix with current confidence and
93 * standard deviation factor.
94 * @throws NullPointerException if covariance matrix has not been provided yet.
95 * @throws InvalidRotationMatrixException if rotation cannot be properly determined.
96 */
97 public Ellipsoid toEllipsoid() throws InvalidRotationMatrixException {
98 return toEllipsoid(standardDeviationFactor);
99 }
100
101 /**
102 * Flattens accuracy representation to 2D by taking into account only x and y coordinates and
103 * ignoring variance related to z coordinates.
104 *
105 * @return flattened accuracy representation in 2D.
106 * @throws NullPointerException if covariance matrix is not defined.
107 * @throws GeometryException if intersection cannot be computed.
108 */
109 public Accuracy2D flattenTo2D() throws GeometryException {
110 // get intersected ellipse for unitary standard deviation
111 final var ellipse = intersectWithPlane(1.0);
112
113 final var semiMajorAxis = ellipse.getSemiMajorAxis();
114 final var semiMinorAxis = ellipse.getSemiMinorAxis();
115 final var rotation = ellipse.getRotation();
116
117 final var u = rotation.asInhomogeneousMatrix();
118 final var s2 = Matrix.diagonal(new double[]{
119 semiMajorAxis * semiMajorAxis,
120 semiMinorAxis * semiMinorAxis});
121
122 try {
123 // compute covariance as the squared matrix M = U*S*V'
124 // Hence: M*M' = U*S*V'*(U*S*V')' = U*S*V'*V'*S*U' = U*S^2*U'
125
126 s2.multiply(u);
127 u.multiply(s2);
128
129 return new Accuracy2D(u, confidence);
130 } catch (final AlgebraException e) {
131 throw new GeometryException(e);
132 }
133 }
134
135 /**
136 * Intersects ellipsoid representing this accuracy with horizontal xy plane.
137 *
138 * @return intersected ellipse.
139 * @throws NullPointerException if covariance matrix is not defined.
140 * @throws GeometryException if intersection cannot be computed.
141 */
142 public Ellipse intersectWithPlane() throws GeometryException {
143 return intersectWithPlane(standardDeviationFactor);
144 }
145
146 /**
147 * Converts provided covariance matrix into a 3D ellipsoid taking into account current
148 * confidence and standard deviation factor.
149 *
150 * @param standardDeviationFactor standard deviation factor.
151 * @return ellipsoid representing accuracy of covariance matrix with provided standard
152 * deviation factor.
153 * @throws NullPointerException if covariance matrix has not been provided yet.
154 * @throws InvalidRotationMatrixException if rotation cannot be properly determined.
155 */
156 private Ellipsoid toEllipsoid(final double standardDeviationFactor)
157 throws InvalidRotationMatrixException {
158 final var semiAxesLengths = ArrayUtils.multiplyByScalarAndReturnNew(
159 sqrtSingularValues, standardDeviationFactor);
160 final var rotation = new MatrixRotation3D(u);
161 return new Ellipsoid(Point3D.create(), semiAxesLengths, rotation);
162 }
163
164 /**
165 * Intersects ellipsoid representing this accuracy with provided standard
166 * deviation factor and with horizontal xy plane.
167 *
168 * @param standardDeviationFactor standard deviation factor.
169 * @return intersected ellipse.
170 * @throws NullPointerException if covariance matrix is not defined.
171 * @throws GeometryException if intersection cannot be computed.
172 */
173 private Ellipse intersectWithPlane(final double standardDeviationFactor) throws GeometryException {
174 final var ellipsoid = toEllipsoid(standardDeviationFactor);
175 final var quadric = ellipsoid.toQuadric();
176
177 // create horizontal xy plane located at ellipsoid center
178 final var center = ellipsoid.getCenter();
179 final var directorVector = new double[]{0.0, 0.0, 1.0};
180 final var plane = new Plane(center, directorVector);
181
182 final var conic = quadric.intersectWith(plane);
183
184 return new Ellipse(conic);
185 }
186 }