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.AlgebraException;
19 import com.irurueta.algebra.Matrix;
20
21 import java.util.ArrayList;
22 import java.util.List;
23
24 /**
25 * This class performs transformations on 3D space.
26 * Transformations can be applied to any 3D geometric figure.
27 */
28 public abstract class Transformation3D {
29
30 /**
31 * Empty constructor.
32 */
33 protected Transformation3D() {
34 }
35
36 /**
37 * Transforms provided point using this transformation and returns a new
38 * one.
39 *
40 * @param inputPoint point to be transformed.
41 * @return a new transformed point.
42 */
43 public Point3D transformAndReturnNew(final Point3D inputPoint) {
44 final var outputPoint = Point3D.create();
45 transform(inputPoint, outputPoint);
46 return outputPoint;
47 }
48
49 /**
50 * Transforms and updates provided point.
51 *
52 * @param point point to be transformed and updated.
53 */
54 public void transform(final Point3D point) {
55 transform(point, point);
56 }
57
58 /**
59 * Transforms input point using this transformation and stores the result in
60 * provided output points.
61 *
62 * @param inputPoint point to be transformed.
63 * @param outputPoint instance where transformed point data will be stored.
64 */
65 public abstract void transform(final Point3D inputPoint, final Point3D outputPoint);
66
67 /**
68 * Transforms provided list of points using this transformation.
69 *
70 * @param inputPoints points to be transformed.
71 * @return new transformed points.
72 */
73 public List<Point3D> transformPointsAndReturnNew(final List<Point3D> inputPoints) {
74 final var outputPoints = new ArrayList<Point3D>(inputPoints.size());
75 transformPoints(inputPoints, outputPoints);
76 return outputPoints;
77 }
78
79 /**
80 * Transforms provided list of points using this transformation and stores
81 * the result in provided output list of points.
82 * Notice that any previous content in output list will be removed when
83 * calling this method.
84 *
85 * @param inputPoints points to be transformed.
86 * @param outputPoints transformed points.
87 */
88 public void transformPoints(final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
89 outputPoints.clear();
90 for (final var point : inputPoints) {
91 outputPoints.add(transformAndReturnNew(point));
92 }
93 }
94
95 /**
96 * Transforms provided list of points using this transformation and
97 * overwriting their previous values.
98 *
99 * @param points points to be transformed and overwritten.
100 */
101 public void transformAndOverwritePoints(final List<Point3D> points) {
102 for (final var point : points) {
103 transform(point, point);
104 }
105 }
106
107 /**
108 * Transforms a quadric using this transformation and returns a new one.
109 *
110 * @param inputQuadric quadric to be transformed.
111 * @return a new transformed quadric.
112 * @throws NonSymmetricMatrixException raised if due to numerical precision
113 * the resulting output quadric matrix is not considered to be symmetric.
114 * @throws AlgebraException raised if transform cannot be computed because of
115 * numerical instabilities.
116 */
117 public Quadric transformAndReturnNew(final Quadric inputQuadric) throws NonSymmetricMatrixException,
118 AlgebraException {
119 final var outputQuadric = new Quadric();
120 transform(inputQuadric, outputQuadric);
121 return outputQuadric;
122 }
123
124 /**
125 * Transforms and updates provided quadric.
126 *
127 * @param quadric quadric to be transformed.
128 * @throws NonSymmetricMatrixException raised if due to numerical precision
129 * the resulting quadric matrix is not considered to be symmetric.
130 * @throws AlgebraException raised if transform cannot be computed because of
131 * numerical instabilities.
132 */
133 public void transform(final Quadric quadric) throws NonSymmetricMatrixException, AlgebraException {
134 transform(quadric, quadric);
135 }
136
137 /**
138 * Transforms a quadric using this transformation and stores the result into
139 * provided output quadric.
140 *
141 * @param inputQuadric quadric to be transformed.
142 * @param outputQuadric instance where data of transformed quadric will be
143 * stored.
144 * @throws NonSymmetricMatrixException raised if due to numerical precision
145 * the resulting output quadric matrix is not considered to be symmetric.
146 * @throws AlgebraException raised if transform cannot be computed because of
147 * numerical instabilities.
148 */
149 public abstract void transform(final Quadric inputQuadric, final Quadric outputQuadric)
150 throws NonSymmetricMatrixException, AlgebraException;
151
152 /**
153 * Transforms a dual quadric using this transformation and returns a new
154 * one.
155 *
156 * @param inputDualQuadric dual quadric to be transformed.
157 * @return a new transformed dual quadric.
158 * @throws NonSymmetricMatrixException raised if due to numerical precision
159 * the resulting output dual quadric matrix is not considered to be
160 * symmetric.
161 * @throws AlgebraException raised if transform cannot be computed because
162 * of numerical instabilities.
163 */
164 public DualQuadric transformAndReturnNew(final DualQuadric inputDualQuadric)
165 throws NonSymmetricMatrixException, AlgebraException {
166 final var outputDualQuadric = new DualQuadric();
167 transform(inputDualQuadric, outputDualQuadric);
168 return outputDualQuadric;
169 }
170
171 /**
172 * Transforms and updates a dual quadric using this transformation.
173 *
174 * @param dualQuadric dual quadric to be transformed.
175 * @throws NonSymmetricMatrixException raised if due to numerical precision
176 * the resulting output dual quadric matrix is not considered to be
177 * symmetric.
178 * @throws AlgebraException raised if transform cannot be computed because
179 * of numerical instabilities.
180 */
181 public void transform(final DualQuadric dualQuadric) throws NonSymmetricMatrixException, AlgebraException {
182 transform(dualQuadric, dualQuadric);
183 }
184
185 /**
186 * Transforms a dual quadric using this transformation and stores the result
187 * into provided output dual quadric.
188 *
189 * @param inputDualQuadric dual quadric to be transformed.
190 * @param outputDualQuadric instance where data of transformed dual quadric
191 * will be stored.
192 * @throws NonSymmetricMatrixException Raised if due to numerical precision
193 * the resulting output dual quadric matrix is not considered to be
194 * symmetric.
195 * @throws AlgebraException raised if transform cannot be computed because
196 * of numerical instabilities.
197 */
198 public abstract void transform(final DualQuadric inputDualQuadric, final DualQuadric outputDualQuadric)
199 throws NonSymmetricMatrixException, AlgebraException;
200
201 /**
202 * Transforms provided plane using this transformation and returns a new
203 * one.
204 *
205 * @param inputPlane plane to be transformed.
206 * @return a new transformed plane.
207 * @throws AlgebraException raised if transform cannot be computed because
208 * of numerical instabilities.
209 */
210 public Plane transformAndReturnNew(final Plane inputPlane) throws AlgebraException {
211 final var outputPlane = new Plane();
212 transform(inputPlane, outputPlane);
213 return outputPlane;
214 }
215
216 /**
217 * Transforms and updates provided plane using this transformation.
218 *
219 * @param plane plane to be transformed.
220 * @throws AlgebraException raised if transform cannot be computed because
221 * of numerical instabilities.
222 */
223 public void transform(final Plane plane) throws AlgebraException {
224 transform(plane, plane);
225 }
226
227 /**
228 * Transforms provided input plane using this transformation and stores the
229 * result into provided output plane instance.
230 *
231 * @param inputPlane plane to be transformed.
232 * @param outputPlane instance where data of transformed plane will be
233 * stored.
234 * @throws AlgebraException raised if transform cannot be computed because
235 * of numerical instabilities.
236 */
237 public abstract void transform(final Plane inputPlane, final Plane outputPlane) throws AlgebraException;
238
239 /**
240 * Transforms provided list of planes using this transformation.
241 *
242 * @param inputPlanes planes to be transformed.
243 * @return transformed planes.
244 * @throws AlgebraException raised if transform cannot be computed because
245 * of numerical instabilities.
246 */
247 public List<Plane> transformPlanesAndReturnNew(final List<Plane> inputPlanes) throws AlgebraException {
248 final var outputPlanes = new ArrayList<Plane>(inputPlanes.size());
249 transformPlanes(inputPlanes, outputPlanes);
250 return outputPlanes;
251 }
252
253 /**
254 * Transforms provided list of planes using this transformation and stores
255 * the result in provided output list of planes.
256 * Notice that any previous content in output list will be removed when
257 * calling this method.
258 *
259 * @param inputPlanes planes to be transformed.
260 * @param outputPlanes transformed planes.
261 * @throws AlgebraException raised if transform cannot be computed because
262 * of numerical instabilities.
263 */
264 public void transformPlanes(final List<Plane> inputPlanes, final List<Plane> outputPlanes) throws AlgebraException {
265 outputPlanes.clear();
266 for (final var plane : inputPlanes) {
267 outputPlanes.add(transformAndReturnNew(plane));
268 }
269 }
270
271 /**
272 * Transforms provided list of planes using this transformation and
273 * overwriting their previous values.
274 *
275 * @param planes planes to be transformed and overwritten.
276 * @throws AlgebraException raised if transform cannot be computed because
277 * of numerical instabilities.
278 */
279 public void transformAndOverwritePlanes(final List<Plane> planes) throws AlgebraException {
280 for (final var plane : planes) {
281 transform(plane, plane);
282 }
283 }
284
285 /**
286 * Transforms provided line using this transformation and returns a new one.
287 *
288 * @param inputLine line to be transformed.
289 * @return transformed line.
290 * @throws CoincidentPlanesException raised if transformation is degenerate
291 * and results in planes forming a line being coincident.
292 * @throws AlgebraException raised if transform cannot be computed because
293 * of numerical instabilities.
294 */
295 public Line3D transformAndReturnNew(final Line3D inputLine) throws CoincidentPlanesException, AlgebraException {
296 final var plane1 = transformAndReturnNew(inputLine.getPlane1());
297 final var plane2 = transformAndReturnNew(inputLine.getPlane2());
298
299 return new Line3D(plane1, plane2);
300 }
301
302 /**
303 * Transforms and updates provided line using this transformation.
304 *
305 * @param line line to be transformed.
306 * @throws CoincidentPlanesException raised if transformation is degenerate
307 * and results in planes forming a line being coincident.
308 * @throws AlgebraException raised if transform cannot be computed because
309 * of numerical instabilities.
310 */
311 public void transform(final Line3D line) throws CoincidentPlanesException, AlgebraException {
312 transform(line, line);
313 }
314
315 /**
316 * Transforms provided input line using this transformation and stores the
317 * result into provided output line instance.
318 *
319 * @param inputLine line to be transformed.
320 * @param outputLine instance where data of transformed line will be stored.
321 * @throws CoincidentPlanesException Raised if transformation is degenerate
322 * and results in planes forming a line being coincident.
323 * @throws AlgebraException raised if transform cannot be computed because
324 * of numerical instabilities.
325 */
326 public void transform(final Line3D inputLine, final Line3D outputLine) throws CoincidentPlanesException,
327 AlgebraException {
328
329 final var plane1 = transformAndReturnNew(inputLine.getPlane1());
330 final var plane2 = transformAndReturnNew(inputLine.getPlane2());
331
332 outputLine.setPlanes(plane1, plane2);
333 }
334
335 /**
336 * Transforms provided list of lines using this transformation.
337 *
338 * @param inputLines lines to be transformed.
339 * @return transformed lines.
340 * @throws CoincidentPlanesException raised if transformation is degenerate
341 * and results in planes forming a line being coincident.
342 * @throws AlgebraException raised if transform cannot be computed because
343 * of numerical instabilities.
344 */
345 public List<Line3D> transformLines(final List<Line3D> inputLines) throws CoincidentPlanesException,
346 AlgebraException {
347 final var outputLines = new ArrayList<Line3D>(inputLines.size());
348 transformLines(inputLines, outputLines);
349 return outputLines;
350 }
351
352 /**
353 * Transforms provided list of lines using this transformation and stores
354 * the result in provided output list of lines.
355 * Notice that any previous content in output list will be removed when
356 * calling this method.
357 *
358 * @param inputLines lines to be transformed.
359 * @param outputLines transformed lines.
360 * @throws CoincidentPlanesException raised if transformation is degenerate
361 * and results in planes forming a line being coincident.
362 * @throws AlgebraException raised if transform cannot be computed because
363 * of numerical instabilities.
364 */
365 public void transformLines(
366 final List<Line3D> inputLines, final List<Line3D> outputLines) throws CoincidentPlanesException,
367 AlgebraException {
368
369 outputLines.clear();
370 for (final var line : inputLines) {
371 outputLines.add(transformAndReturnNew(line));
372 }
373 }
374
375 /**
376 * Transforms provided list of lines using this transformation and
377 * overwriting their previous values.
378 *
379 * @param lines lines to be transformed and overwritten.
380 * @throws CoincidentPlanesException raised if transformation is degenerate
381 * and results in planes forming a line being coincident.
382 * @throws AlgebraException raised if transform cannot be computed because
383 * of numerical instabilities.
384 */
385 public void transformAndOverwriteLines(final List<Line3D> lines) throws CoincidentPlanesException,
386 AlgebraException {
387
388 for (final var line : lines) {
389 transform(line, line);
390 }
391 }
392
393 /**
394 * Transforms provided polygon using this transformation and returns a new
395 * one.
396 *
397 * @param inputPolygon polygon to be transformed.
398 * @return a new transformed polygon.
399 */
400 public Polygon3D transformAndReturnNew(final Polygon3D inputPolygon) {
401 final var outVertices = transformPointsAndReturnNew(inputPolygon.getVertices());
402 try {
403 return new Polygon3D(outVertices);
404 } catch (final NotEnoughVerticesException ignore) {
405 // this will never happen because all existing polygons have enough
406 // vertices
407 return null;
408 }
409 }
410
411 /**
412 * Transforms and updates provided polygon using this transformation.
413 *
414 * @param polygon polygon to be transformed.
415 */
416 public void transform(final Polygon3D polygon) {
417 transformAndOverwritePoints(polygon.getVertices());
418 }
419
420 /**
421 * Transforms provided input polygon using this transformation and stores
422 * the result into provided output polygon instance.
423 *
424 * @param inputPolygon polygon to be transformed.
425 * @param outputPolygon Instance where transformed polygon data will be
426 * stored.
427 */
428 public void transform(final Polygon3D inputPolygon, final Polygon3D outputPolygon) {
429 try {
430 outputPolygon.setVertices(transformPointsAndReturnNew(inputPolygon.getVertices()));
431 } catch (final NotEnoughVerticesException ignore) {
432 // this will never happen because all existing polygons have enough
433 // vertices
434 }
435 }
436
437 /**
438 * Transforms provided triangle using this transformation and returns a new
439 * one.
440 *
441 * @param inputTriangle triangle to be transformed.
442 * @return a new transformed triangle.
443 */
444 public Triangle3D transformAndReturnNew(final Triangle3D inputTriangle) {
445 final var vertex1 = transformAndReturnNew(inputTriangle.getVertex1());
446 final var vertex2 = transformAndReturnNew(inputTriangle.getVertex2());
447 final var vertex3 = transformAndReturnNew(inputTriangle.getVertex3());
448 return new Triangle3D(vertex1, vertex2, vertex3);
449 }
450
451 /**
452 * Transforms and updates provided input triangle using this transformation.
453 *
454 * @param triangle triangle to be transformed.
455 */
456 public void transform(final Triangle3D triangle) {
457 transform(triangle, triangle);
458 }
459
460 /**
461 * Transforms provided input triangle using this transformation and stores
462 * the result into provided output triangle instance.
463 *
464 * @param inputTriangle triangle to be transformed.
465 * @param outputTriangle instance where transformed triangle data will be
466 * stored.
467 */
468 public void transform(final Triangle3D inputTriangle, final Triangle3D outputTriangle) {
469 transform(inputTriangle.getVertex1(), outputTriangle.getVertex1());
470 transform(inputTriangle.getVertex2(), outputTriangle.getVertex2());
471 transform(inputTriangle.getVertex3(), outputTriangle.getVertex3());
472 }
473
474 /**
475 * Represents this transformation as a 4x4 matrix.
476 * A point can be transformed as T * p, where T is the transformation matrix
477 * and p is a point expressed as an homogeneous vector.
478 *
479 * @return this transformation in matrix form.
480 */
481 public abstract Matrix asMatrix();
482
483 /**
484 * Represents this transformation as a 4x4 matrix and stores the result in
485 * provided instance.
486 *
487 * @param m instance where transformation matrix will be stored.
488 * @throws IllegalArgumentException raised if provided instance is not a 3x3
489 * matrix.
490 */
491 public abstract void asMatrix(final Matrix m);
492
493 /**
494 * Transforms a camera using this transformation.
495 *
496 * @param camera camera to be transformed.
497 * @return transformed quadric.
498 * @throws AlgebraException raised if transform cannot be computed because
499 * of numerical instabilities.
500 */
501 public PinholeCamera transformAndReturnNew(final PinholeCamera camera) throws AlgebraException {
502 final var outputCamera = new PinholeCamera();
503 transform(camera, outputCamera);
504 return outputCamera;
505 }
506
507 /**
508 * Transforms and updates provided camera using this transformation.
509 *
510 * @param camera camera to be transformed.
511 * @throws AlgebraException raised if transform cannot be computed because
512 * of numerical instabilities.
513 */
514 public void transform(final PinholeCamera camera) throws AlgebraException {
515 transform(camera, camera);
516 }
517
518 /**
519 * Transforms a camera using this transformation and stores the result into
520 * provided output camera.
521 *
522 * @param inputCamera camera to be transformed.
523 * @param outputCamera instance where data of transformed camera will be
524 * stored.
525 * @throws AlgebraException raised if transform cannot be computed because
526 * of numerical instabilities.
527 */
528 public abstract void transform(final PinholeCamera inputCamera, final PinholeCamera outputCamera)
529 throws AlgebraException;
530 }