View Javadoc
1   /*
2    * Copyright (C) 2012 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.Matrix;
19  import com.irurueta.algebra.Utils;
20  import com.irurueta.algebra.WrongSizeException;
21  
22  import java.io.Serializable;
23  
24  /**
25   * Class defining the base interface of any possible conic.
26   * Appropriate subclasses should be used for each conic type: pure conics and
27   * dual conics.
28   */
29  public abstract class BaseConic implements Serializable {
30      /**
31       * Number of rows of one matrix that contains conic parameters.
32       */
33      public static final int BASECONIC_MATRIX_ROW_SIZE = 3;
34  
35      /**
36       * Number of columns of one matrix that contains conic parameters.
37       */
38      public static final int BASECONIC_MATRIX_COLUMN_SIZE = 3;
39  
40      /**
41       * Number of parameters on a conic or dual conic.
42       */
43      public static final int N_PARAMS = 6;
44  
45      /**
46       * Threshold above zero used to determine whether a point lies inside
47       * (is locus of) the given conic or not.
48       */
49      public static final double DEFAULT_LOCUS_THRESHOLD = 1e-12;
50  
51      /**
52       * Threshold above zero used to determine whether two points of a conic
53       * are perpendicular or not.
54       */
55      public static final double DEFAULT_PERPENDICULAR_THRESHOLD = 1e-12;
56  
57      /**
58       * Minimum allowed threshold.
59       */
60      public static final double MIN_THRESHOLD = 0.0;
61  
62      /**
63       * Threshold above zero to determine whether one matrix is symmetric or not.
64       */
65      private static final double DEFAULT_SYMMETRIC_THRESHOLD = 1e-12;
66  
67      /**
68       * Machine precision.
69       */
70      private static final double PRECISION = 1e-12;
71  
72      /**
73       * "A" element of the matrix defining a conic.
74       */
75      protected double a;
76  
77      /**
78       * B element of the matrix defining a conic.
79       */
80      protected double b;
81  
82      /**
83       * C element of the matrix defining a conic.
84       */
85      protected double c;
86  
87      /**
88       * D element of the matrix defining a conic.
89       */
90      private double d;
91  
92      /**
93       * E element of the matrix defining a conic.
94       */
95      private double e;
96  
97      /**
98       * F element of the matrix defining a conic.
99       */
100     private double f;
101 
102     /**
103      * Determines whether this instance is already mNormalized.
104      */
105     private boolean normalized;
106 
107     /**
108      * Constructor of this class.
109      */
110     protected BaseConic() {
111         a = b = c = d = e = f = 0.0;
112         normalized = false;
113     }
114 
115     /**
116      * Constructor of this class. This constructor accepts every parameter
117      * describing a base conic (parameters a, b, c, d, e, f).
118      *
119      * @param a Parameter A of the base conic
120      * @param b Parameter B of the base conic.
121      * @param c Parameter C of the base conic.
122      * @param d Parameter D of the base conic.
123      * @param e Parameter E of the base conic.
124      * @param f Parameter F of the base conic.
125      */
126     protected BaseConic(final double a, final double b, final double c, final double d, final double e,
127                         final double f) {
128         setParameters(a, b, c, d, e, f);
129     }
130 
131     /**
132      * Constructor. This constructor accepts a Matrix describing a base conic.
133      *
134      * @param m 3x3 matrix describing a base conic.
135      * @throws NonSymmetricMatrixException Raised when the conic matrix is not
136      *                                     symmetric.
137      * @throws IllegalArgumentException    Raised when the size of the matrix is
138      *                                     not 3x3.
139      */
140     protected BaseConic(final Matrix m) throws NonSymmetricMatrixException {
141         setParameters(m);
142     }
143 
144     /**
145      * Returns parameter A of the given base conic.
146      *
147      * @return Parameter A of a matrix describing a base conic.
148      */
149     public double getA() {
150         return a;
151     }
152 
153     /**
154      * Returns parameter B of the given base conic.
155      *
156      * @return Parameter B of a matrix describing a base conic.
157      */
158     public double getB() {
159         return b;
160     }
161 
162     /**
163      * Returns parameter C of the given base conic.
164      *
165      * @return Parameter C of a matrix describing a base conic.
166      */
167     public double getC() {
168         return c;
169     }
170 
171     /**
172      * Returns parameter D of the given base conic.
173      *
174      * @return Parameter D of a matrix describing a base conic.
175      */
176     public double getD() {
177         return d;
178     }
179 
180     /**
181      * Returns parameter E of the given base conic.
182      *
183      * @return Parameter E of a matrix describing a base conic.
184      */
185     public double getE() {
186         return e;
187     }
188 
189     /**
190      * Returns parameter F of the given base conic.
191      *
192      * @return Parameter F of a matrix describing a base conic.
193      */
194     public double getF() {
195         return f;
196     }
197 
198     /**
199      * This method accepts every parameter describing a base conic (parameters
200      * a, b, c, d, e, f).
201      *
202      * @param a Parameter A of the base conic.
203      * @param b Parameter B of the base conic.
204      * @param c Parameter C of the base conic.
205      * @param d Parameter D of the base conic.
206      * @param e Parameter E of the base conic.
207      * @param f Parameter F of the base conic.
208      */
209     public final void setParameters(final double a, final double b, final double c, final double d, final double e,
210                                     final double f) {
211         this.a = a;
212         this.b = b;
213         this.c = c;
214         this.d = d;
215         this.e = e;
216         this.f = f;
217         normalized = false;
218     }
219 
220     /**
221      * This method sets the matrix used for describing a base conic.
222      * This matrix must be 3x3 and symmetric.
223      *
224      * @param m                  3x3 Matrix describing a base conic.
225      * @param symmetricThreshold Grade of tolerance to determine whether a
226      *                           matrix is symmetric or not. Because of machine precision,
227      *                           the values may not be exactly equal. (by default:
228      *                           DEFAULT_SYMMETRIC_THRESHOLD is used).
229      * @throws IllegalArgumentException    Raised when the size of the matrix is
230      *                                     not 3x3.
231      * @throws NonSymmetricMatrixException Raised when the conic matrix is not
232      *                                     symmetric.
233      */
234     @SuppressWarnings("DuplicatedCode")
235     public final void setParameters(final Matrix m, final double symmetricThreshold)
236             throws NonSymmetricMatrixException {
237         if (m.getRows() != BASECONIC_MATRIX_ROW_SIZE || m.getColumns() != BASECONIC_MATRIX_COLUMN_SIZE) {
238             throw new IllegalArgumentException();
239         } else {
240             if (!Utils.isSymmetric(m, symmetricThreshold)) {
241                 throw new NonSymmetricMatrixException();
242             } else {
243                 a = m.getElementAt(0, 0);
244                 b = m.getElementAt(0, 1);
245                 c = m.getElementAt(1, 1);
246                 d = m.getElementAt(0, 2);
247                 e = m.getElementAt(1, 2);
248                 f = m.getElementAt(2, 2);
249                 normalized = false;
250             }
251         }
252     }
253 
254     /**
255      * This method sets the matrix used for describing a base conic.
256      * This matrix must be 3x3 and symmetric.
257      *
258      * @param m 3x3 Matrix describing a base conic.
259      * @throws IllegalArgumentException    Raised when the size of the matrix is
260      *                                     not 3x3.
261      * @throws NonSymmetricMatrixException Raised when the conic matrix is not
262      *                                     symmetric.
263      */
264     public final void setParameters(final Matrix m) throws NonSymmetricMatrixException {
265         setParameters(m, DEFAULT_SYMMETRIC_THRESHOLD);
266     }
267 
268     /**
269      * This method sets the A parameter of a base conic.
270      *
271      * @param a Parameter A of the given base conic.
272      */
273     public void setA(final double a) {
274         this.a = a;
275         normalized = false;
276     }
277 
278     /**
279      * This method sets the B parameter of a base conic.
280      *
281      * @param b Parameter B of the given base conic.
282      */
283     public void setB(final double b) {
284         this.b = b;
285         normalized = false;
286     }
287 
288     /**
289      * This method sets the C parameter of a base conic.
290      *
291      * @param c Parameter C of the given base conic.
292      */
293     public void setC(final double c) {
294         this.c = c;
295         normalized = false;
296     }
297 
298     /**
299      * This method sets the D parameter of a base conic.
300      *
301      * @param d Parameter D of the given base conic.
302      */
303     public void setD(final double d) {
304         this.d = d;
305         normalized = false;
306     }
307 
308     /**
309      * This method sets the E parameter of a base conic.
310      *
311      * @param e Parameter E of the given base conic.
312      */
313     public void setE(final double e) {
314         this.e = e;
315         normalized = false;
316     }
317 
318     /**
319      * This method sets the F parameter of a base conic.
320      *
321      * @param f Parameter F of the given base conic.
322      */
323     public void setF(final double f) {
324         this.f = f;
325         normalized = false;
326     }
327 
328     /**
329      * Returns the matrix that describes this base conic.
330      *
331      * @return 3x3 matrix describing this base conic.
332      */
333     public Matrix asMatrix() {
334         Matrix out = null;
335         try {
336             out = new Matrix(BASECONIC_MATRIX_ROW_SIZE, BASECONIC_MATRIX_COLUMN_SIZE);
337             asMatrix(out);
338         } catch (final WrongSizeException ignore) {
339             // never happens
340         }
341         return out;
342     }
343 
344     /**
345      * Sets the values in provided matrix corresponding to this base conic.
346      *
347      * @param m Provided matrix where values will be stored
348      * @throws IllegalArgumentException Raised if provided matrix is not 3x3
349      */
350     public void asMatrix(final Matrix m) {
351 
352         if (m.getRows() != BASECONIC_MATRIX_ROW_SIZE || m.getColumns() != BASECONIC_MATRIX_ROW_SIZE) {
353             throw new IllegalArgumentException();
354         }
355 
356         m.setElementAt(0, 0, a);
357         m.setElementAt(0, 1, b);
358         m.setElementAt(0, 2, d);
359         m.setElementAt(1, 0, b);
360         m.setElementAt(1, 1, c);
361         m.setElementAt(1, 2, e);
362         m.setElementAt(2, 0, d);
363         m.setElementAt(2, 1, e);
364         m.setElementAt(2, 2, f);
365     }
366 
367     /**
368      * Normalizes the Conic params using its norm
369      */
370     public void normalize() {
371         if (!normalized) {
372             final var m = asMatrix();
373             final var norm = Utils.normF(m);
374 
375             if (!Double.isNaN(norm) && norm > PRECISION) {
376                 a /= norm;
377                 b /= norm;
378                 c /= norm;
379                 d /= norm;
380                 e /= norm;
381                 f /= norm;
382                 normalized = true;
383             }
384         }
385     }
386 
387     /**
388      * Returns boolean indicating whether this base conic has already been
389      * normalized.
390      *
391      * @return True if normalized, false otherwise.
392      */
393     public boolean isNormalized() {
394         return normalized;
395     }
396 }