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 }