Updated readability of the code.
[sixth-3d.git] / src / main / java / eu / svjatoslav / sixth / e3d / geometry / Point3D.java
1 /*
2  * Sixth 3D engine. Author: Svjatoslav Agejenko.
3  * This project is released under Creative Commons Zero (CC0) license.
4  */
5 package eu.svjatoslav.sixth.e3d.geometry;
6
7 import static java.lang.Math.*;
8
9 /**
10  * Used to represent point in a 3D space or vector.
11  */
12
13 public class Point3D implements Cloneable {
14
15     // coordinates
16     public double x, y, z;
17
18     public Point3D() {
19     }
20
21     public Point3D(final double x, final double y, final double z) {
22         this.x = x;
23         this.y = y;
24         this.z = z;
25     }
26
27     public Point3D(final float x, final float y, final float z) {
28         this.x = x;
29         this.y = y;
30         this.z = z;
31     }
32
33     public Point3D(final int x, final int y, final int z) {
34         this.x = x;
35         this.y = y;
36         this.z = z;
37     }
38
39     /**
40      * Creates new current point by cloning coordinates from parent point.
41      */
42     public Point3D(final Point3D parent) {
43         x = parent.x;
44         y = parent.y;
45         z = parent.z;
46     }
47
48     /**
49      * Add other point to current point. Value of other point will not be changed.
50      *
51      * @param otherPoint point to add.
52      * @return current point.
53      */
54     public Point3D add(final Point3D otherPoint) {
55         x += otherPoint.x;
56         y += otherPoint.y;
57         z += otherPoint.z;
58         return this;
59     }
60
61     /**
62      * Add coordinates of current point to other point. Value of current point will not be changed.
63      *
64      * @return current point.
65      */
66     public Point3D addTo(final Point3D... otherPoints) {
67         for (final Point3D otherPoint : otherPoints) otherPoint.add(this);
68         return this;
69     }
70
71     /**
72      * Create new point by cloning position of current point.
73      *
74      * @return newly created clone.
75      */
76     public Point3D clone() {
77         return new Point3D(this);
78     }
79
80     /**
81      * Copy coordinates from other point to current point. Value of other point will not be changed.
82      */
83     public Point3D clone(final Point3D otherPoint) {
84         x = otherPoint.x;
85         y = otherPoint.y;
86         z = otherPoint.z;
87         return this;
88     }
89
90     /**
91      * Set current point coordinates to the middle point between two other points.
92      *
93      * @param p1 first point.
94      * @param p2 second point.
95      * @return current point.
96      */
97     public Point3D computeMiddlePoint(final Point3D p1, final Point3D p2) {
98         x = (p1.x + p2.x) / 2d;
99         y = (p1.y + p2.y) / 2d;
100         z = (p1.z + p2.z) / 2d;
101         return this;
102     }
103
104     /**
105      * @return true if current point coordinates are equal to zero.
106      */
107     public boolean isZero() {
108         return (x == 0) && (y == 0) && (z == 0);
109     }
110
111     public double getAngleXZ(final Point3D anotherPoint) {
112         return Math.atan2(x - anotherPoint.x, z - anotherPoint.z);
113     }
114
115     public double getAngleYZ(final Point3D anotherPoint) {
116         return Math.atan2(y - anotherPoint.y, z - anotherPoint.z);
117     }
118
119     public double getAngleXY(final Point3D anotherPoint) {
120         return Math.atan2(x - anotherPoint.x, y - anotherPoint.y);
121     }
122
123     /**
124      * Compute distance to another point.
125      *
126      * @param anotherPoint point to compute distance to.
127      * @return distance to another point.
128      */
129     public double getDistanceTo(final Point3D anotherPoint) {
130         final double xDelta = x - anotherPoint.x;
131         final double yDelta = y - anotherPoint.y;
132         final double zDelta = z - anotherPoint.z;
133
134         return sqrt(((xDelta * xDelta) + (yDelta * yDelta) + (zDelta * zDelta)));
135     }
136
137     /**
138      * @return length of current vector.
139      */
140     public double getVectorLength() {
141         return sqrt(((x * x) + (y * y) + (z * z)));
142     }
143
144     /**
145      * Invert current point coordinates.
146      *
147      * @return current point.
148      */
149     public Point3D invert() {
150         x = -x;
151         y = -y;
152         z = -z;
153         return this;
154     }
155
156     /**
157      * Rotate current point around center point by angleXZ and angleYZ.
158      * <p>
159      * See also: <a href="https://marctenbosch.com/quaternions/">Let's remove Quaternions from every 3D Engine</a>
160      *
161      * @param center  center point.
162      * @param angleXZ angle around XZ axis.
163      * @param angleYZ angle around YZ axis.
164      */
165     public Point3D rotate(final Point3D center, final double angleXZ,
166                           final double angleYZ) {
167         final double s1 = sin(angleXZ);
168         final double c1 = cos(angleXZ);
169
170         final double s2 = sin(angleYZ);
171         final double c2 = cos(angleYZ);
172
173         x -= center.x;
174         y -= center.y;
175         z -= center.z;
176
177         final double y1 = (z * s2) + (y * c2);
178         final double z1 = (z * c2) - (y * s2);
179
180         final double x1 = (z1 * s1) + (x * c1);
181         final double z2 = (z1 * c1) - (x * s1);
182
183         x = x1 + center.x;
184         y = y1 + center.y;
185         z = z2 + center.z;
186
187         return this;
188     }
189
190     public Point3D rotate(final double angleXZ, final double angleYZ) {
191         return rotate(new Point3D(0, 0, 0), angleXZ, angleYZ);
192     }
193
194     /**
195      * Round current point coordinates to integer values.
196      */
197     public void roundToInteger() {
198         x = (int) x;
199         y = (int) y;
200         z = (int) z;
201     }
202
203     /**
204      * Scale down current point by factor.
205      * All coordinates will be divided by factor.
206      *
207      * @param factor factor to scale by.
208      * @return current point.
209      */
210     public Point3D scaleDown(final double factor) {
211         x /= factor;
212         y /= factor;
213         z /= factor;
214         return this;
215     }
216
217     /**
218      * Scale up current point by factor.
219      * All coordinates will be multiplied by factor.
220      *
221      * @param factor factor to scale by.
222      * @return current point.
223      */
224     public Point3D scaleUp(final double factor) {
225         x *= factor;
226         y *= factor;
227         z *= factor;
228         return this;
229     }
230
231     /**
232      * Set current point coordinates to given values.
233      *
234      * @param x X coordinate.
235      * @param y Y coordinate.
236      * @param z Z coordinate.
237      */
238     public void setValues(final double x, final double y, final double z) {
239         this.x = x;
240         this.y = y;
241         this.z = z;
242     }
243
244     /**
245      * Subtract other point from current point. Value of other point will not be changed.
246      *
247      * @return current point.
248      */
249     public Point3D subtract(final Point3D otherPoint) {
250         x -= otherPoint.x;
251         y -= otherPoint.y;
252         z -= otherPoint.z;
253         return this;
254     }
255
256     @Override
257     public String toString() {
258         return "x:" + x + " y:" + y + " z:" + z;
259     }
260
261     /**
262      * Translate current point along X axis by given increment.
263      *
264      * @return current point.
265      */
266     public Point3D translateX(final double xIncrement) {
267         x += xIncrement;
268         return this;
269     }
270
271     /**
272      * Translate current point along Y axis by given increment.
273      *
274      * @return current point.
275      */
276     public Point3D translateY(final double yIncrement) {
277         y += yIncrement;
278         return this;
279     }
280
281     /**
282      * Translate current point along Z axis by given increment.
283      *
284      * @return current point.
285      */
286     public Point3D translateZ(final double zIncrement) {
287         z += zIncrement;
288         return this;
289     }
290
291     /**
292      * Here we assume that Z coordinate is distance to the viewer.
293      * If Z is positive, then point is in front of the viewer, and therefore it is visible.
294      *
295      * @return point visibility status.
296      */
297     public boolean isVisible() {
298         return z > 0;
299     }
300
301     /**
302      * Resets point coordinates to zero along all axes.
303      *
304      * @return current point.
305      */
306     public Point3D zero() {
307         x = 0;
308         y = 0;
309         z = 0;
310         return this;
311     }
312
313 }