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