View Javadoc
1   /*
2    * Copyright (C) 2017 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  package com.irurueta.geometry;
17  
18  import com.irurueta.algebra.AlgebraException;
19  
20  import java.io.Serializable;
21  import java.util.Arrays;
22  
23  /**
24   * This class defines an ellipsoid.
25   */
26  public class Ellipsoid implements Serializable {
27  
28      /**
29       * Number of dimensions.
30       */
31      public static final int DIMENSIONS = 3;
32  
33      /**
34       * Constant to compute approximate surface area.
35       */
36      private static final double P = 1.6075;
37  
38      /**
39       * Center of ellipse.
40       */
41      private Point3D center;
42  
43  
44      /**
45       * Lengths of all three semi-axes.
46       */
47      private double[] semiAxesLengths;
48  
49      /**
50       * Rotation.
51       */
52      private Rotation3D rotation;
53  
54      /**
55       * Empty constructor.
56       * Creates an ellipsoid equal to a sphere located at space origin (0,0,0)
57       * with radius 1.0.
58       */
59      public Ellipsoid() {
60          center = Point3D.create();
61          semiAxesLengths = new double[DIMENSIONS];
62          Arrays.fill(semiAxesLengths, 1.0);
63          rotation = Rotation3D.create();
64      }
65  
66      /**
67       * Sets ellipsoid parameters.
68       *
69       * @param center          center of ellipsoid.
70       * @param semiAxesLengths lengths of all three semi-axes.
71       * @param rotation        rotation.
72       * @throws IllegalArgumentException if length of provided array is not
73       *                                  three.
74       */
75      public Ellipsoid(final Point3D center, final double[] semiAxesLengths, final Rotation3D rotation) {
76          setCenterAxesAndRotation(center, semiAxesLengths, rotation);
77      }
78  
79      /**
80       * Returns center of ellipsoid.
81       *
82       * @return center of ellipsoid.
83       */
84      public Point3D getCenter() {
85          return center;
86      }
87  
88      /**
89       * Sets center of ellipsoid.
90       *
91       * @param center center of ellipsoid.
92       * @throws NullPointerException raised if provided center is null.
93       */
94      public void setCenter(final Point3D center) {
95          if (center == null) {
96              throw new NullPointerException();
97          }
98          this.center = center;
99      }
100 
101     /**
102      * Gets lengths of all three semi-axes.
103      *
104      * @return lengths of all three semi-axes.
105      */
106     public double[] getSemiAxesLengths() {
107         return semiAxesLengths;
108     }
109 
110     /**
111      * Sets lengths of all three semi-axes.
112      *
113      * @param semiAxesLengths lengths of all three semi-axes.
114      * @throws IllegalArgumentException if length of provided array is not
115      *                                  three.
116      */
117     public void setSemiAxesLengths(final double[] semiAxesLengths) {
118         if (semiAxesLengths.length != DIMENSIONS) {
119             throw new IllegalArgumentException();
120         }
121         this.semiAxesLengths = semiAxesLengths;
122     }
123 
124     /**
125      * Gets rotation.
126      *
127      * @return rotation.
128      */
129     public Rotation3D getRotation() {
130         return rotation;
131     }
132 
133     /**
134      * Sets rotation.
135      *
136      * @param rotation rotation.
137      */
138     public void setRotation(final Rotation3D rotation) {
139         this.rotation = rotation;
140     }
141 
142     /**
143      * Sets ellipsoid parameters.
144      *
145      * @param center          center of ellipsoid.
146      * @param semiAxesLengths lengths of all three semi-axes.
147      * @param rotation        rotation.
148      * @throws IllegalArgumentException if length of provided array is not
149      *                                  three.
150      */
151     public final void setCenterAxesAndRotation(
152             final Point3D center, final double[] semiAxesLengths, final Rotation3D rotation) {
153         if (semiAxesLengths.length != DIMENSIONS) {
154             throw new IllegalArgumentException();
155         }
156         this.center = center;
157         this.semiAxesLengths = semiAxesLengths;
158         this.rotation = rotation;
159     }
160 
161     /**
162      * Returns volume of this ellipsoid.
163      *
164      * @return volume of this ellipsoid.
165      */
166     public double getVolume() {
167         final var a = semiAxesLengths[0];
168         final var b = semiAxesLengths[1];
169         final var c = semiAxesLengths[2];
170         return 4.0 / 3.0 * Math.PI * a * b * c;
171     }
172 
173     /**
174      * Returns surface of this ellipsoid.
175      *
176      * @return surface of this ellipsoid.
177      */
178     public double getSurface() {
179         final var a = semiAxesLengths[0];
180         final var b = semiAxesLengths[1];
181         final var c = semiAxesLengths[2];
182 
183         return 4.0 * Math.PI * Math.pow((Math.pow(a * b, P) + Math.pow(a * c, P) + Math.pow(b * c, P)) / 3.0, 1.0 / P);
184     }
185 
186     /**
187      * Converts this ellipsoid into a quadric.
188      * Quadrics a re a more general representation of ellipsoids.
189      *
190      * @return a quadric representing this ellipsoid.
191      * @throws GeometryException if quadric cannot be determined due to
192      *                           numerical instabilities.
193      */
194     public Quadric toQuadric() throws GeometryException {
195         // A quadric has the following matrix form:
196         // Q =   [A  D   F   G]
197         //       [D  B   E   H]
198         //       [F  E   C   I]
199         //       [G  H   I   J]
200         // [x y z w][A D F G][x] = [x y z w][A*x + D*y + F*z + G*w] =
201         //          [D B E H][y]            [D*x + B*y + E*z + H*w]
202         //          [F E C I][z]            [F*x + E*y + C*z + I*w]
203         //          [G H I J][w]            [G*x + H*y + I*z + J*w]
204         // = A*x^2 + D*x*y + F*x*z + G*x*w + D*x*y + B*y^2 + E*y*z + H*y*w +
205         // F*x*z + E*y*z + C*z^2 + I*z*w + G*x*w + H*y*w + I*z*w + J*w^2 =
206         // = A*x^2 + B*y^2 + C*z^2 + 2*D*x*y + 2*E*y*z + 2*F*x*z + 2*G*x*w + 2*H*y*w + 2*I*z*w + J*w^2
207         // which follows expression:
208         // A*x^2 + B*y^2 + C*z^2 + 2*D*x*y + 2*E*y*z + 2*F*x*z + 2*G*x*w + 2*H*y*w + 2*I*z*w + J*w^2 = 0
209 
210         // An Ellipsoid is a particular form of a quadric following expression:
211         // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 = 1
212         // when centered at origin and having no rotation
213 
214         // if we take an arbitrary center position:
215         final var a = 1.0 / Math.pow(semiAxesLengths[0], 2.0);
216         final var b = 1.0 / Math.pow(semiAxesLengths[1], 2.0);
217         final var c = 1.0 / Math.pow(semiAxesLengths[2], 2.0);
218         final var d = 0.0;
219         final var e = 0.0;
220         final var f = 0.0;
221         final var g = 0.0;
222         final var h = 0.0;
223         final var i = 0.0;
224         final var j = -1;
225 
226         final var q = new Quadric(a, b, c, d, e, f, g, h, i, j);
227         final var t = new EuclideanTransformation3D(rotation, new double[]{
228                 center.getInhomX(), center.getInhomY(), center.getInhomZ()});
229 
230         try {
231             t.transform(q);
232         } catch (final NonSymmetricMatrixException | AlgebraException ex) {
233             throw new GeometryException(ex);
234         }
235 
236         return q;
237     }
238 
239     /**
240      * Sets parameters of this ellipsoid from a sphere.
241      *
242      * @param sphere a sphere to set parameters from.
243      */
244     public final void setFromSphere(final Sphere sphere) {
245         center = sphere.getCenter();
246         Arrays.fill(semiAxesLengths, sphere.getRadius());
247         rotation = Rotation3D.create();
248     }
249 }