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  
17  package com.irurueta.geometry;
18  
19  import java.io.Serializable;
20  import java.util.Objects;
21  
22  /**
23   * Subclass of Point2D defining an inhomogeneous 2D point.
24   * An inhomogeneous 2D point is defined by two coordinates: (x, y), where x and
25   * y are the horizontal and vertical coordinates, respectively.
26   * Homogeneous 2D points can be transformed into inhomogeneous ones by
27   * normalizing both x and y coordinates by the w factor as follows:
28   * Homogeneous 2d point (x,y,w) -< Inhomogeneous 2D point (x/w,y/w).
29   * Note that if and homogeneous 2D point is at infinity (w=0), its corresponding
30   * inhomogeneous point will be at infinity by setting (x=inf,y=inf). Because of
31   * this, and because of machine precision, usually Homogeneous points are better
32   * suited when working at far distances or for numerical purposes, and their
33   * inhomogeneous counterparts are better suited when computing Euclidean
34   * distances, etc.
35   */
36  public class InhomogeneousPoint2D extends Point2D implements Serializable {
37  
38      /**
39       * Defines the X coordinate of an inhomogeneous 2D point.
40       */
41      private double x;
42  
43      /**
44       * Defines the Y coordinate of an inhomogeneous 2D point.
45       */
46      private double y;
47  
48      /**
49       * Empty constructor.
50       */
51      public InhomogeneousPoint2D() {
52          super();
53          x = y = 0.0;
54      }
55  
56      /**
57       * Constructor of this class. This constructor sets a new inhomogeneous v
58       * array containing the coordinates X and Y of the given point.
59       *
60       * @param v Array of length 2 containing the 2D coordinates of an
61       *          inhomogeneous point.
62       * @throws IllegalArgumentException Raised when the size of the array is not
63       *                                  2.
64       */
65      public InhomogeneousPoint2D(final double[] v) {
66          super();
67          setCoordinates(v);
68      }
69  
70      /**
71       * Constructor of this class. This constructor sets a new inhomogeneous 2D
72       * point using the coordinates x and y of the given point.
73       *
74       * @param x X coordinate of the given 2D point.
75       * @param y Y coordinate of the given 2D point.
76       */
77      public InhomogeneousPoint2D(final double x, final double y) {
78          this.x = x;
79          this.y = y;
80      }
81  
82      /**
83       * This constructor sets a new inhomogeneous 2D point using as
84       * initialization provided Point2D instance.
85       *
86       * @param point Point to initialize new instance to.
87       */
88      public InhomogeneousPoint2D(final Point2D point) {
89          setCoordinates(point);
90      }
91  
92      /**
93       * Returns the X coordinate of the given homogeneous 2D point instance.
94       *
95       * @return X coordinate.
96       */
97      public double getX() {
98          return x;
99      }
100 
101     /**
102      * Sets the X coordinate of this homogeneous point.
103      *
104      * @param x X coordinate.
105      */
106     public void setX(final double x) {
107         this.x = x;
108     }
109 
110     /**
111      * Returns the Y coordinate of the given homogeneous 2D point instance.
112      *
113      * @return Y coordinate.
114      */
115     public double getY() {
116         return y;
117     }
118 
119     /**
120      * Sets the Y coordinate of this homogeneous point.
121      *
122      * @param y Y coordinate.
123      */
124     public void setY(final double y) {
125         this.y = y;
126     }
127 
128     /**
129      * Sets the coordinates of this inhomogeneous 2D point by using provided X
130      * and Y coordinates.
131      *
132      * @param x X coordinate.
133      * @param y Y coordinate.
134      */
135     public void setCoordinates(final double x, final double y) {
136         this.x = x;
137         this.y = y;
138     }
139 
140     /**
141      * Sets the coordinates of a 2D point using an array containing its
142      * coordinates.
143      *
144      * @param v Array containing the coordinates of the point.
145      * @throws IllegalArgumentException Raised if provided array does not have a
146      *                                  valid size.
147      */
148     @Override
149     public final void setCoordinates(final double[] v) {
150         if (v.length != POINT2D_INHOMOGENEOUS_COORDINATES_LENGTH) {
151             throw new IllegalArgumentException();
152         } else {
153             x = v[0];
154             y = v[1];
155         }
156     }
157 
158     /**
159      * Sets coordinates of this instance using the coordinates of provided 2D
160      * point.
161      *
162      * @param point Input point.
163      */
164     @Override
165     public final void setCoordinates(final Point2D point) {
166         switch (point.getType()) {
167             case INHOMOGENEOUS_COORDINATES:
168                 final var inhomPoint = (InhomogeneousPoint2D) point;
169                 x = inhomPoint.getX();
170                 y = inhomPoint.getY();
171                 break;
172             case HOMOGENEOUS_COORDINATES:
173             default:
174                 final var homPoint = (HomogeneousPoint2D) point;
175                 x = homPoint.getInhomX();
176                 y = homPoint.getInhomY();
177                 break;
178         }
179     }
180 
181     /**
182      * Returns X homogeneous coordinate of this 2d point.
183      *
184      * @return X homogeneous coordinate.
185      */
186     @Override
187     public double getHomX() {
188         return getX();
189     }
190 
191     /**
192      * Returns Y homogeneous coordinate of this 2d point.
193      *
194      * @return Y homogeneous coordinate.
195      */
196     @Override
197     public double getHomY() {
198         return getY();
199     }
200 
201     /**
202      * Returns W homogeneous coordinate of this 2d point.
203      *
204      * @return W homogeneous coordinate.
205      */
206     @Override
207     public double getHomW() {
208         return 1.0;
209     }
210 
211     /**
212      * Sets coordinates of this 2d point instance using provided homogeneous
213      * coordinates.
214      *
215      * @param homX x homogeneous coordinate.
216      * @param homY y homogeneous coordinate.
217      * @param homW w homogeneous coordinate.
218      */
219     @Override
220     public void setHomogeneousCoordinates(final double homX, final double homY, final double homW) {
221         x = homX / homW;
222         y = homY / homW;
223     }
224 
225     /**
226      * Returns X inhomogeneous coordinate of this 2d point.
227      *
228      * @return X inhomogeneous coordinate.
229      */
230     @Override
231     public double getInhomX() {
232         return getX();
233     }
234 
235     /**
236      * Sets X inhomogeneous coordinate of this 2d point.
237      *
238      * @param inhomX inhomogeneous coordinate.
239      */
240     @Override
241     public void setInhomX(final double inhomX) {
242         x = inhomX;
243     }
244 
245     /**
246      * Returns Y inhomogeneous coordinate of this 2d point.
247      *
248      * @return Y inhomogeneous coordinate.
249      */
250     @Override
251     public double getInhomY() {
252         return getY();
253     }
254 
255     /**
256      * Sets Y inhomogeneous coordinate of this 2d point.
257      *
258      * @param inhomY Y inhomogeneous coordinate.
259      */
260     @Override
261     public void setInhomY(final double inhomY) {
262         y = inhomY;
263     }
264 
265     /**
266      * Sets coordinates of this 2d point instance using provided inhomogeneous
267      * coordinates.
268      *
269      * @param inhomX x inhomogeneous coordinate.
270      * @param inhomY y inhomogeneous coordinate.
271      */
272     @Override
273     public void setInhomogeneousCoordinates(final double inhomX, final double inhomY) {
274         setCoordinates(inhomX, inhomY);
275     }
276 
277     /**
278      * Checks if provided object equals current 2D point.
279      *
280      * @param obj Object to compare.
281      * @return True if both objects are considered to be equal, false otherwise.
282      */
283     @Override
284     public boolean equals(final Object obj) {
285         if (!(obj instanceof Point2D point)) {
286             return false;
287         }
288         if (obj == this) {
289             return true;
290         }
291 
292         return equals(point);
293     }
294 
295     /**
296      * Returns hash code value.
297      *
298      * @return Hash code value.
299      */
300     @Override
301     public int hashCode() {
302         return Objects.hash(x, y, 1.0);
303     }
304 
305     /**
306      * Checks if the homogeneous 2d point described by this instance equals the
307      * input {@link Point2D} (using a comparison threshold).
308      *
309      * @param point     Point that will be compared to.
310      * @param threshold threshold grade of tolerance to determine whether the
311      *                  points are equal or not. It is used because due to machine precision, the
312      *                  values might not be exactly equal (if not provided
313      *                  DEFAULT_COMPARISON_THRESHOLD is used).
314      * @return True if current point and input point are the same, false
315      * otherwise.
316      * @throws IllegalArgumentException Raised if threshold is negative.
317      */
318     @Override
319     public boolean equals(final Point2D point, final double threshold) {
320         if (point.getType() == CoordinatesType.INHOMOGENEOUS_COORDINATES) {
321             return equals((InhomogeneousPoint2D) point, threshold);
322         } else {
323             return equals((HomogeneousPoint2D) point, threshold);
324         }
325     }
326 
327     /**
328      * Checks if the homogeneous 2d point described by this instance equals the
329      * input HomogeneousPoint2d (using a comparison threshold).
330      *
331      * @param point     Point that will be compared to.
332      * @param threshold threshold grade of tolerance to determine whether the
333      *                  points are equal or not. It is used because due to machine precision, the
334      *                  values might not be exactly equal (if not provided
335      *                  DEFAULT_COMPARISON_THRESHOLD is used).
336      * @return True if current point and input point are the same, false
337      * otherwise.
338      * @throws IllegalArgumentException Raised if threshold is negative.
339      */
340     public boolean equals(final HomogeneousPoint2D point, final double threshold) {
341         if (threshold < MIN_THRESHOLD) {
342             throw new IllegalArgumentException();
343         }
344 
345         final var dX = Math.abs((point.getX() / point.getW()) - x) <= threshold;
346         final var dY = Math.abs((point.getY() / point.getW()) - y) <= threshold;
347 
348         return (dX && dY);
349     }
350 
351     /**
352      * Checks if the homogeneous 2d point described by this instance equals the
353      * input HomogeneousPoint2d (using a comparison threshold).
354      *
355      * @param point Point that will be compared to.
356      * @return True if current point and input point are the same, false
357      * otherwise.
358      */
359     public boolean equals(final HomogeneousPoint2D point) {
360         return equals(point, DEFAULT_COMPARISON_THRESHOLD);
361     }
362 
363     /**
364      * Checks if the homogeneous 2d point described by this instance equals the
365      * input InhomogeneousPoint2d (using a comparison threshold).
366      *
367      * @param point     Point that will be compared to.
368      * @param threshold threshold grade of tolerance to determine whether the
369      *                  points are equal or not. It is used because due to machine precision, the
370      *                  values might not be exactly equal (if not provided
371      *                  DEFAULT_COMPARISON_THRESHOLD is used).
372      * @return True if current point and input point are the same, false
373      * otherwise.
374      * @throws IllegalArgumentException Raised if threshold is negative.
375      */
376     public boolean equals(final InhomogeneousPoint2D point, final double threshold) {
377         if (threshold < MIN_THRESHOLD) {
378             throw new IllegalArgumentException();
379         }
380 
381         final var dX = Math.abs(point.getX() - x) <= threshold;
382         final var dY = Math.abs(point.getY() - y) <= threshold;
383 
384         return (dX && dY);
385     }
386 
387     /**
388      * Checks if the homogeneous 2d point described by this instance equals the
389      * input InhomogeneousPoint2d (using a comparison threshold).
390      *
391      * @param point Point that will be compared to.
392      * @return True if current point and input point are the same, false
393      * otherwise.
394      */
395     public boolean equals(final InhomogeneousPoint2D point) {
396         return equals(point, DEFAULT_COMPARISON_THRESHOLD);
397     }
398 
399     /**
400      * Checks whether this Point2D is at infinity or not.
401      *
402      * @return True if the point is at infinity. False otherwise.
403      */
404     @Override
405     public boolean isAtInfinity() {
406         return (Double.isInfinite(x) || Double.isNaN(x) || Double.isInfinite(y) || Double.isNaN(y));
407     }
408 
409     /**
410      * Returns the type of coordinates used to represent a Point2D.
411      *
412      * @return Type of coordinates of this 2d point.
413      */
414     @Override
415     public CoordinatesType getType() {
416         return CoordinatesType.INHOMOGENEOUS_COORDINATES;
417     }
418 
419     /**
420      * Converts this instance into an homogeneous 2D point and returns the
421      * result as a new homogeneous 2D point instance.
422      *
423      * @return Converts and returns this point as an homogeneous 2D point.
424      */
425     public HomogeneousPoint2D toHomogeneous() {
426         return new HomogeneousPoint2D(x, y, 1.0);
427     }
428 
429     /**
430      * Returns an array containing the coordinates of this Point2D.
431      *
432      * @return Array containing coordinates of this Point2D.
433      */
434     @Override
435     public double[] asArray() {
436         final var out = new double[POINT2D_INHOMOGENEOUS_COORDINATES_LENGTH];
437         asArray(out);
438         return out;
439     }
440 
441     /**
442      * Uses provided array to store the coordinates of this InhomogeneousPoint2D
443      *
444      * @param array Array where coordinates will be stored.
445      * @throws IllegalArgumentException Raised if length of array is not 2.
446      */
447     @Override
448     public void asArray(final double[] array) {
449         if (array.length != POINT2D_INHOMOGENEOUS_COORDINATES_LENGTH) {
450             throw new IllegalArgumentException();
451         }
452         array[0] = x;
453         array[1] = y;
454     }
455 }