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.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 }