1 /**************************************************************************/
2 /* Copyright 2009 Tim Day */
3 /* */
4 /* This file is part of Fracplanet */
5 /* */
6 /* Fracplanet is free software: you can redistribute it and/or modify */
7 /* it under the terms of the GNU General Public License as published by */
8 /* the Free Software Foundation, either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* Fracplanet is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with Fracplanet. If not, see <http://www.gnu.org/licenses/>. */
18 /**************************************************************************/
19
20 /*! \file
21 \brief Interface for class XYZ.
22 */
23
24 #ifndef _xyz_h_
25 #define _xyz_h_
26
27 #include "common.h"
28 #include "random.h"
29
30 //! Class to hold vectors in 3D cartesian co-ordinates.
31 /*! Direct access to the x,y,z members is permitted.
32 There is a general assumption that the co-ordinate system will be right handed,
33 and that for terrain type applications x and y will be plan position and z will be height.
34 */
35 class XYZ
36 {
37 public:
38
39 float x;
40 float y;
41 float z;
42
43 //! Null constructor.
44 /*! NB The components are not cleared to zero.
45 */
XYZ()46 XYZ()
47 {}
48
49 //! Copy constructor.
XYZ(const XYZ & v)50 XYZ(const XYZ& v)
51 :x(v.x),y(v.y),z(v.z){}
52
53 //! Initialise from separate components.
XYZ(float vx,float vy,float vz)54 XYZ(float vx,float vy,float vz)
55 :x(vx),y(vy),z(vz){}
56
57 //! Destructor.
~XYZ()58 ~XYZ()
59 {}
60
61 typedef float XYZ::* ElementPtr;
62 static ElementPtr element_table[3];
63
64 //! Access by number
element(uint e)65 const float& element(uint e) const
66 {
67 return this->*(element_table[e]);
68 }
69
70 //! Access by number
element(uint e)71 float& element(uint e)
72 {
73 return this->*(element_table[e]);
74 }
75
76 //! Multiply by scalar.
77 void operator*=(float k)
78 {
79 x*=k;
80 y*=k;
81 z*=k;
82 }
83
84 //! Divide by scalar.
85 /*! Implemented assuming one divide and three multiplies is faster than three divides.
86 */
87 void operator/=(float k)
88 {
89 const float ik(1.0/k);
90 x*=ik;
91 y*=ik;
92 z*=ik;
93 }
94
95 //! Vector addition.
96 void operator+=(const XYZ& v)
97 {
98 x+=v.x;
99 y+=v.y;
100 z+=v.z;
101 }
102
103 //! Vector subtraction.
104 void operator-=(const XYZ& v)
105 {
106 x-=v.x;
107 y-=v.y;
108 z-=v.z;
109 }
110
111 //! Assignment.
assign(const XYZ & v)112 void assign(const XYZ& v)
113 {
114 x=v.x;
115 y=v.y;
116 z=v.z;
117 }
118
119 //! Negation.
120 const XYZ operator-() const
121 {
122 return XYZ(-x,-y,-z);
123 }
124
125 //! Return the square of the magnitude.
magnitude2()126 float magnitude2() const
127 {
128 return x*x+y*y+z*z;
129 }
130
131 //! Return the magnitude.
magnitude()132 float magnitude() const
133 {
134 return sqrt(magnitude2());
135 }
136
137 //! Return the vector normalised.
138 const XYZ normalised() const;
139
140 //! Normalise this vector.
141 void normalise();
142
143 //! Write the vector (spaces as separators).
144 std::ostream& write(std::ostream&) const;
145
146 //! Alternate formatting.
147 const std::string format_comma() const;
148
149 //! Alternate formatting.
150 const std::string format_blender() const;
151
152 //! Alternate formatting.
153 const std::string format_pov() const;
154 };
155
156 //! Cross product.
157 inline const XYZ operator*(const XYZ& a,const XYZ& b)
158 {
159 return XYZ(
160 a.y*b.z-a.z*b.y,
161 a.z*b.x-a.x*b.z,
162 a.x*b.y-a.y*b.x
163 );
164 }
165
166 //! Dot product.
167 /*! Perhaps a curious choice of operator but it works for me.
168 */
169 inline float operator%(const XYZ& a,const XYZ& b)
170 {
171 return a.x*b.x+a.y*b.y+a.z*b.z;
172 }
173
174 //! Vector addition.
175 inline const XYZ operator+(const XYZ& a,const XYZ& b)
176 {
177 return XYZ(a.x+b.x,a.y+b.y,a.z+b.z);
178 }
179
180 //! Vector subtraction.
181 inline const XYZ operator-(const XYZ& a,const XYZ& b)
182 {
183 return XYZ(a.x-b.x,a.y-b.y,a.z-b.z);
184 }
185
186 //! Multiplication by scalar.
187 inline const XYZ operator*(float k,const XYZ& v)
188 {
189 return XYZ(k*v.x,k*v.y,k*v.z);
190 }
191
192 //! Multiplication by scalar.
193 inline const XYZ operator*(const XYZ& v,float k)
194 {
195 return XYZ(k*v.x,k*v.y,k*v.z);
196 }
197
198 //! Division by scalar.
199 inline const XYZ operator/(const XYZ& v,float k)
200 {
201 return (1.0/k)*v;
202 }
203
204 //! Equality operator.
205 inline bool operator==(const XYZ& a,const XYZ& b)
206 {
207 return (a.x==b.x && a.y==b.y && a.z==b.z);
208 }
209
210 //! Inequality operator.
211 inline bool operator!=(const XYZ& a,const XYZ& b)
212 {
213 return (a.x!=b.x || a.y!=b.y || a.z!=b.z);
214 }
215
216 /*! Will fail assertion if the co-ordinate has zero magnitude.
217 */
normalised()218 inline const XYZ XYZ::normalised() const
219 {
220 const float m=magnitude();
221 assert(m!=0.0);
222 return (*this)/m;
223 }
224
225 /*! Will fail assertion if the co-ordinate has zero magnitude.
226 */
normalise()227 inline void XYZ::normalise()
228 {
229 (*this)=normalised();
230 }
231
232 //! Stream output operator.
233 inline std::ostream& operator<<(std::ostream& out,const XYZ& v)
234 {
235 return v.write(out);
236 }
237
238 //! Generates a random point in the cube bounded by (0,0,0) and (1.0,1.0,1.0)
239 class RandomXYZInUnitCube : public XYZ
240 {
241 public:
242 RandomXYZInUnitCube(Random01&);
243 };
244
245 //! Generates random points in a recnangular box centred on the origin
246 class RandomXYZInBox : public XYZ
247 {
248 public:
249 RandomXYZInBox(Random01& rng,const XYZ& bounds);
250 };
251
252 //! Generates a random point in or on a unit-radius sphere centred on the origin.
253 class RandomXYZInSphere : public XYZ
254 {
255 public:
256 RandomXYZInSphere(Random01& rng,float radius);
257 };
258
259 //! Generates a random point in or on an origin-centred ellipsoid with semi-axes of the specified size.
260 class RandomXYZInEllipsoid : public XYZ
261 {
262 public:
263 RandomXYZInEllipsoid(Random01& rng,const XYZ& axes);
264 };
265
266 //! Generates a random point on the surface of a unit-radius sphere
267 class RandomXYZSphereNormal : public XYZ
268 {
269 public:
270 RandomXYZSphereNormal(Random01& rng);
271 };
272
273 #endif
274