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 }