Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutorial3/src/libraries/util/Math.cc @ 10396

Last change on this file since 10396 was 8400, checked in by rgrieder, 14 years ago

Removed strange hack. Extensive tests while watching Top Gear have revealed that it isn't necessary anymore.

  • Property svn:eol-style set to native
File size: 14.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of several math-functions.
32*/
33
34#include "Math.h"
35
36#include <OgrePlane.h>
37
38#include "MathConvert.h"
39#include "SubString.h"
40
41namespace orxonox
42{
43#if OGRE_VERSION < 0x010603
44    /**
45        @brief Function for writing a Radian to a stream.
46    */
47    std::ostream& operator<<(std::ostream& out, const orxonox::Radian& radian)
48    {
49        out << radian.valueRadians();
50        return out;
51    }
52
53    /**
54        @brief Function for writing a Degree to a stream.
55    */
56    std::ostream& operator<<(std::ostream& out, const orxonox::Degree& degree)
57    {
58        out << degree.valueDegrees();
59        return out;
60    }
61#endif
62
63    /**
64        @brief Function for reading a Radian from a stream.
65    */
66    std::istream& operator>>(std::istream& in, orxonox::Radian& radian)
67    {
68        float temp;
69        in >> temp;
70        radian = temp;
71        return in;
72    }
73
74    /**
75        @brief Function for reading a Degree from a stream.
76    */
77    std::istream& operator>>(std::istream& in, orxonox::Degree& degree)
78    {
79        float temp;
80        in >> temp;
81        degree = temp;
82        return in;
83    }
84
85
86    /**
87        @brief Gets the angle between my viewing direction and the direction to the position of the other object.
88        @param myposition My position
89        @param mydirection My viewing direction
90        @param otherposition The position of the other object
91        @return The angle in radian
92
93        Examples:
94         - If the other object is exactly in front of me, the function returns 0.
95         - If the other object is exactly behind me, the function returns pi.
96         - If the other object is exactly right/left to me (or above/below), the function returns pi/2.
97    */
98    float getAngle(const orxonox::Vector3& myposition, const orxonox::Vector3& mydirection, const orxonox::Vector3& otherposition)
99    {
100        orxonox::Vector3 distance = otherposition - myposition;
101        float distancelength = distance.length();
102        if (distancelength == 0)
103            return 0;
104        else
105            return acos(clamp<float>(mydirection.dotProduct(distance) / distancelength, -1, 1));
106    }
107
108    /**
109        @brief Gets the 2D viewing direction (up/down, left/right) to the position of the other object.
110        @param myposition My position
111        @param mydirection My viewing direction
112        @param myorthonormal My orthonormalvector (pointing upwards through my head)
113        @param otherposition The position of the other object
114        @return The viewing direction
115
116        Examples:
117         - If the other object is exactly in front of me, the function returns <tt>Vector2(0, 0)</tt>.
118         - If the other object is exactly at my left, the function returns <tt>Vector2(-1, 0)</tt>.
119         - If the other object is exactly at my right, the function returns <tt>Vector2(1, 0)</tt>.
120         - If the other object is only a bit at my right, the function still returns <tt>Vector2(1, 0)</tt>.
121         - If the other object is exactly above me, the function returns <tt>Vector2(0, 1)</tt>.
122    */
123    orxonox::Vector2 get2DViewdirection(const orxonox::Vector3& myposition, const orxonox::Vector3& mydirection, const orxonox::Vector3& myorthonormal, const orxonox::Vector3& otherposition)
124    {
125        orxonox::Vector3 distance = otherposition - myposition;
126
127        // project difference vector on our plane
128        orxonox::Vector3 projection = Ogre::Plane(mydirection, myposition).projectVector(distance);
129
130        float projectionlength = projection.length();
131        if (projectionlength == 0)
132        {
133            if (myposition.dotProduct(otherposition) >= 0)
134                return orxonox::Vector2(0, 0);
135            else
136                return orxonox::Vector2(0, 1);
137        }
138
139        float cos_value = clamp<float>(myorthonormal.dotProduct(projection) / projectionlength, -1, 1);
140        float sin_value = sqrt( 1 - cos_value*cos_value );
141
142        if ((mydirection.crossProduct(myorthonormal)).dotProduct(distance) > 0)
143            return orxonox::Vector2( sin_value, cos_value );
144        else
145            return orxonox::Vector2( -sin_value, cos_value );
146    }
147
148    /**
149        @brief Gets the 2D viewing direction (up/down, left/right) to the position of the other object, multiplied with the viewing distance to the object (0° = 0, 180° = 1).
150        @param myposition My position
151        @param mydirection My viewing direction
152        @param myorthonormal My orthonormalvector (pointing upwards through my head)
153        @param otherposition The position of the other object
154        @return The viewing direction
155
156        Examples:
157         - If the other object is exactly in front of me, the function returns <tt>Vector2(0, 0)</tt>.
158         - If the other object is exactly at my left, the function returns <tt>Vector2(-0.5, 0)</tt>.
159         - If the other object is exactly at my right, the function returns <tt>Vector2(0.5, 0)</tt>.
160         - If the other object is only a bit at my right, the function still returns <tt>Vector2(0.01, 0)</tt>.
161         - If the other object is exactly above me, the function returns <tt>Vector2(0, 0.5)</tt>.
162    */
163    orxonox::Vector2 get2DViewcoordinates(const orxonox::Vector3& myposition, const orxonox::Vector3& mydirection, const orxonox::Vector3& myorthonormal, const orxonox::Vector3& otherposition)
164    {
165        orxonox::Vector3 distance = otherposition - myposition;
166
167        // project difference vector on our plane
168        orxonox::Vector3 projection = Ogre::Plane(mydirection, myposition).projectVector(distance);
169
170        float projectionlength = projection.length();
171        if (projectionlength == 0)
172        {
173            if (myposition.dotProduct(otherposition) >= 0)
174                return orxonox::Vector2(0, 0);
175            else
176                return orxonox::Vector2(0, 1);
177        }
178        //float angle = acos(clamp<float>(myorthonormal.dotProduct(projection) / projectionlength, -1, 1));
179
180        float cos_value = clamp<float>(myorthonormal.dotProduct(projection) / projectionlength, -1, 1);
181        float sin_value = sqrt( 1 - cos_value*cos_value );
182
183        float distancelength = distance.length();
184        if (distancelength == 0) return orxonox::Vector2(0, 0);
185        float radius = acos(clamp<float>(mydirection.dotProduct(distance) / distancelength, -1, 1)) / math::pi;
186
187        if ((mydirection.crossProduct(myorthonormal)).dotProduct(distance) > 0)
188            return orxonox::Vector2( sin_value * radius, cos_value * radius);
189        else
190            return orxonox::Vector2( -sin_value * radius, cos_value * radius);
191    }
192
193    /**
194        @brief Returns the predicted position I have to aim at, if I want to hit a moving target with a moving projectile.
195        @param myposition My position
196        @param projectilespeed The speed of my projectile
197        @param targetposition The position of my target
198        @param targetvelocity The velocity of my target
199        @return The predicted position
200
201        The function predicts the position based on a linear velocity of the target. If the target changes speed or direction, the projectile will miss.
202    */
203    orxonox::Vector3 getPredictedPosition(const orxonox::Vector3& myposition, float projectilespeed, const orxonox::Vector3& targetposition, const orxonox::Vector3& targetvelocity)
204    {
205        float squaredProjectilespeed = projectilespeed * projectilespeed;
206        orxonox::Vector3 distance = targetposition - myposition;
207        float a = distance.squaredLength();
208        float b = 2 * (distance.x + distance.y + distance.z) * (targetvelocity.x + targetvelocity.y + targetvelocity.z);
209        float c = targetvelocity.squaredLength();
210
211        float temp = 4*squaredProjectilespeed*c + a*a - 4*b*c;
212        if (temp < 0)
213            return orxonox::Vector3::ZERO;
214
215        temp = sqrt(temp);
216        float time = (temp + a) / (2 * (squaredProjectilespeed - b));
217        return (targetposition + targetvelocity * time);
218    }
219
220    /**
221        @brief Returns a unique number. This function will never return the same value twice.
222    */
223    unsigned long getUniqueNumber()
224    {
225        static unsigned long aNumber = 135;
226        return aNumber++;
227    }
228
229
230    //////////////////////////
231    // Conversion functions //
232    //////////////////////////
233
234    // std::string to Vector2
235    bool ConverterFallback<std::string, orxonox::Vector2>::convert(orxonox::Vector2* output, const std::string& input)
236    {
237        size_t opening_parenthesis, closing_parenthesis = input.find('}');
238        if ((opening_parenthesis = input.find('{')) == std::string::npos)
239            opening_parenthesis = 0;
240        else
241            opening_parenthesis++;
242
243        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
244                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
245        if (tokens.size() >= 2)
246        {
247            if (!convertValue(&(output->x), tokens[0]))
248                return false;
249            if (!convertValue(&(output->y), tokens[1]))
250                return false;
251
252            return true;
253        }
254        return false;
255    }
256
257    // std::string to Vector3
258    bool ConverterFallback<std::string, orxonox::Vector3>::convert(orxonox::Vector3* output, const std::string& input)
259    {
260        size_t opening_parenthesis, closing_parenthesis = input.find('}');
261        if ((opening_parenthesis = input.find('{')) == std::string::npos)
262            opening_parenthesis = 0;
263        else
264            opening_parenthesis++;
265
266        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
267                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
268        if (tokens.size() >= 3)
269        {
270            if (!convertValue(&(output->x), tokens[0]))
271                return false;
272            if (!convertValue(&(output->y), tokens[1]))
273                return false;
274            if (!convertValue(&(output->z), tokens[2]))
275                return false;
276
277            return true;
278        }
279        return false;
280    }
281
282    // std::string to Vector4
283    bool ConverterFallback<std::string, orxonox::Vector4>::convert(orxonox::Vector4* output, const std::string& input)
284    {
285        size_t opening_parenthesis, closing_parenthesis = input.find('}');
286        if ((opening_parenthesis = input.find('{')) == std::string::npos)
287            opening_parenthesis = 0;
288        else
289            opening_parenthesis++;
290
291        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
292                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
293        if (tokens.size() >= 4)
294        {
295            if (!convertValue(&(output->x), tokens[0]))
296                return false;
297            if (!convertValue(&(output->y), tokens[1]))
298                return false;
299            if (!convertValue(&(output->z), tokens[2]))
300                return false;
301            if (!convertValue(&(output->w), tokens[3]))
302                return false;
303
304            return true;
305        }
306        return false;
307    }
308
309    // std::string to Quaternion
310    bool ConverterFallback<std::string, orxonox::Quaternion>::convert(orxonox::Quaternion* output, const std::string& input)
311    {
312        size_t opening_parenthesis, closing_parenthesis = input.find('}');
313        if ((opening_parenthesis = input.find('{')) == std::string::npos)
314            opening_parenthesis = 0;
315        else
316            opening_parenthesis++;
317
318        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
319        if (tokens.size() >= 4)
320        {
321            if (!convertValue(&(output->w), tokens[0]))
322                return false;
323            if (!convertValue(&(output->x), tokens[1]))
324                return false;
325            if (!convertValue(&(output->y), tokens[2]))
326                return false;
327            if (!convertValue(&(output->z), tokens[3]))
328                return false;
329
330            return true;
331        }
332        return false;
333    }
334
335    // std::string to ColourValue
336    bool ConverterFallback<std::string, orxonox::ColourValue>::convert(orxonox::ColourValue* output, const std::string& input)
337    {
338        size_t opening_parenthesis, closing_parenthesis = input.find('}');
339        if ((opening_parenthesis = input.find('{')) == std::string::npos)
340            opening_parenthesis = 0;
341        else
342            opening_parenthesis++;
343
344        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
345        if (tokens.size() >= 3)
346        {
347            if (!convertValue(&(output->r), tokens[0]))
348                return false;
349            if (!convertValue(&(output->g), tokens[1]))
350                return false;
351            if (!convertValue(&(output->b), tokens[2]))
352                return false;
353            if (tokens.size() >= 4)
354            {
355                if (!convertValue(&(output->a), tokens[3]))
356                    return false;
357            }
358            else
359                output->a = 1.0;
360
361            return true;
362        }
363        return false;
364    }
365}
Note: See TracBrowser for help on using the repository browser.