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