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