Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/util/Math.cc @ 4577

Last change on this file since 4577 was 3304, checked in by rgrieder, 15 years ago

Merged netp6 branch back to the trunk.

  • Property svn:eol-style set to native
File size: 13.8 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// Do not remove this include, it avoids linker errors.
41#include "mbool.h"
42
43namespace orxonox
44{
45    /**
46        @brief Function for writing a Radian to a stream.
47    */
48    std::ostream& operator<<(std::ostream& out, const orxonox::Radian& radian)
49    {
50        out << radian.valueRadians();
51        return out;
52    }
53
54    /**
55        @brief Function for reading a Radian from a stream.
56    */
57    std::istream& operator>>(std::istream& in, orxonox::Radian& radian)
58    {
59        float temp;
60        in >> temp;
61        radian = temp;
62        return in;
63    }
64
65    /**
66        @brief Function for writing a Degree to a stream.
67    */
68    std::ostream& operator<<(std::ostream& out, const orxonox::Degree& degree)
69    {
70        out << degree.valueDegrees();
71        return out;
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
92
93        @example
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        @example
117        If the other object is exactly in front of me, the function returns Vector2(0, 0).
118        If the other object is exactly at my left, the function returns Vector2(-1, 0).
119        If the other object is exactly at my right, the function returns Vector2(1, 0).
120        If the other object is only a bit at my right, the function still returns Vector2(1, 0).
121        If the other object is exactly above me, the function returns Vector2(0, 1).
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        @example
157        If the other object is exactly in front of me, the function returns Vector2(0, 0).
158        If the other object is exactly at my left, the function returns Vector2(-0.5, 0).
159        If the other object is exactly at my right, the function returns Vector2(0.5, 0).
160        If the other object is only a bit at my right, the function still returns Vector2(0.01, 0).
161        If the other object is exactly above me, the function returns Vector2(0, 0.5).
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)) / Ogre::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    unsigned long getUniqueNumber()
221    {
222        static unsigned long aNumber = 135;
223        return aNumber++;
224    }
225
226
227    //////////////////////////
228    // Conversion functions //
229    //////////////////////////
230
231    // std::string to Vector2
232    bool ConverterFallback<std::string, orxonox::Vector2>::convert(orxonox::Vector2* output, const std::string& input)
233    {
234        size_t opening_parenthesis, closing_parenthesis = input.find(')');
235        if ((opening_parenthesis = input.find('(')) == std::string::npos)
236            opening_parenthesis = 0;
237        else
238            opening_parenthesis++;
239
240        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
241                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
242        if (tokens.size() >= 2)
243        {
244            if (!convertValue(&(output->x), tokens[0]))
245                return false;
246            if (!convertValue(&(output->y), tokens[1]))
247                return false;
248
249            return true;
250        }
251        return false;
252    }
253
254    // std::string to Vector3
255    bool ConverterFallback<std::string, orxonox::Vector3>::convert(orxonox::Vector3* output, const std::string& input)
256    {
257        size_t opening_parenthesis, closing_parenthesis = input.find(')');
258        if ((opening_parenthesis = input.find('(')) == std::string::npos)
259            opening_parenthesis = 0;
260        else
261            opening_parenthesis++;
262
263        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
264                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
265        if (tokens.size() >= 3)
266        {
267            if (!convertValue(&(output->x), tokens[0]))
268                return false;
269            if (!convertValue(&(output->y), tokens[1]))
270                return false;
271            if (!convertValue(&(output->z), tokens[2]))
272                return false;
273
274            return true;
275        }
276        return false;
277    }
278
279    // std::string to Vector4
280    bool ConverterFallback<std::string, orxonox::Vector4>::convert(orxonox::Vector4* output, const std::string& input)
281    {
282        size_t opening_parenthesis, closing_parenthesis = input.find(')');
283        if ((opening_parenthesis = input.find('(')) == std::string::npos)
284            opening_parenthesis = 0;
285        else
286            opening_parenthesis++;
287
288        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
289                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
290        if (tokens.size() >= 4)
291        {
292            if (!convertValue(&(output->x), tokens[0]))
293                return false;
294            if (!convertValue(&(output->y), tokens[1]))
295                return false;
296            if (!convertValue(&(output->z), tokens[2]))
297                return false;
298            if (!convertValue(&(output->w), tokens[3]))
299                return false;
300
301            return true;
302        }
303        return false;
304    }
305
306    // std::string to Quaternion
307    bool ConverterFallback<std::string, orxonox::Quaternion>::convert(orxonox::Quaternion* output, const std::string& input)
308    {
309        size_t opening_parenthesis, closing_parenthesis = input.find(')');
310        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
311
312        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
313        if (tokens.size() >= 4)
314        {
315            if (!convertValue(&(output->w), tokens[0]))
316                return false;
317            if (!convertValue(&(output->x), tokens[1]))
318                return false;
319            if (!convertValue(&(output->y), tokens[2]))
320                return false;
321            if (!convertValue(&(output->z), tokens[3]))
322                return false;
323
324            return true;
325        }
326        return false;
327    }
328
329    // std::string to ColourValue
330    bool ConverterFallback<std::string, orxonox::ColourValue>::convert(orxonox::ColourValue* output, const std::string& input)
331    {
332        size_t opening_parenthesis, closing_parenthesis = input.find(')');
333        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
334
335        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
336        if (tokens.size() >= 3)
337        {
338            if (!convertValue(&(output->r), tokens[0]))
339                return false;
340            if (!convertValue(&(output->g), tokens[1]))
341                return false;
342            if (!convertValue(&(output->b), tokens[2]))
343                return false;
344            if (tokens.size() >= 4)
345            {
346                if (!convertValue(&(output->a), tokens[3]))
347                    return false;
348            }
349            else
350                output->a = 1.0;
351
352            return true;
353        }
354        return false;
355    }
356}
Note: See TracBrowser for help on using the repository browser.