Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/util/Math.cc @ 7275

Last change on this file since 7275 was 7184, checked in by rgrieder, 14 years ago

Replaced mathematical constants with a common definition in Math.h.
Use math::pi, math::pi_d (double), math::e, etc. from now on.

  • Property svn:eol-style set to native
File size: 13.8 KB
RevLine 
[1505]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
[1791]29/**
[2087]30    @file
[1791]31    @brief Implementation of several math-functions.
32*/
33
[2087]34#include "Math.h"
35
[1564]36#include <OgrePlane.h>
[3196]37
[2087]38#include "MathConvert.h"
39#include "SubString.h"
[3196]40// Do not remove this include, it avoids linker errors.
[2171]41#include "mbool.h"
[1505]42
[2171]43namespace orxonox
[1505]44{
[6417]45#if OGRE_VERSION < 0x010603
[2171]46    /**
47        @brief Function for writing a Radian to a stream.
48    */
49    std::ostream& operator<<(std::ostream& out, const orxonox::Radian& radian)
50    {
51        out << radian.valueRadians();
52        return out;
53    }
[1505]54
[2171]55    /**
[6417]56        @brief Function for writing a Degree to a stream.
57    */
58    std::ostream& operator<<(std::ostream& out, const orxonox::Degree& degree)
59    {
60        out << degree.valueDegrees();
61        return out;
62    }
63#endif
64
65    /**
[2171]66        @brief Function for reading a Radian from a stream.
67    */
68    std::istream& operator>>(std::istream& in, orxonox::Radian& radian)
69    {
70        float temp;
71        in >> temp;
72        radian = temp;
73        return in;
74    }
[1505]75
[2171]76    /**
77        @brief Function for reading a Degree from a stream.
78    */
79    std::istream& operator>>(std::istream& in, orxonox::Degree& degree)
80    {
81        float temp;
82        in >> temp;
83        degree = temp;
84        return in;
85    }
[1564]86
[1791]87
[2171]88    /**
89        @brief Gets the angle between my viewing direction and the direction to the position of the other object.
90        @param myposition My position
91        @param mydirection My viewing direction
92        @param otherposition The position of the other object
93        @return The angle
[1564]94
[2171]95        @example
96        If the other object is exactly in front of me, the function returns 0.
97        If the other object is exactly behind me, the function returns pi.
98        If the other object is exactly right/left to me (or above/below), the function returns pi/2.
99    */
100    float getAngle(const orxonox::Vector3& myposition, const orxonox::Vector3& mydirection, const orxonox::Vector3& otherposition)
101    {
102        orxonox::Vector3 distance = otherposition - myposition;
103        float distancelength = distance.length();
104        if (distancelength == 0)
105            return 0;
106        else
107            return acos(clamp<float>(mydirection.dotProduct(distance) / distancelength, -1, 1));
108    }
[1791]109
[2171]110    /**
111        @brief Gets the 2D viewing direction (up/down, left/right) to the position of the other object.
112        @param myposition My position
113        @param mydirection My viewing direction
114        @param myorthonormal My orthonormalvector (pointing upwards through my head)
115        @param otherposition The position of the other object
116        @return The viewing direction
[1564]117
[2171]118        @example
119        If the other object is exactly in front of me, the function returns Vector2(0, 0).
120        If the other object is exactly at my left, the function returns Vector2(-1, 0).
121        If the other object is exactly at my right, the function returns Vector2(1, 0).
122        If the other object is only a bit at my right, the function still returns Vector2(1, 0).
123        If the other object is exactly above me, the function returns Vector2(0, 1).
124    */
125    orxonox::Vector2 get2DViewdirection(const orxonox::Vector3& myposition, const orxonox::Vector3& mydirection, const orxonox::Vector3& myorthonormal, const orxonox::Vector3& otherposition)
126    {
127        orxonox::Vector3 distance = otherposition - myposition;
[1564]128
[2171]129        // project difference vector on our plane
130        orxonox::Vector3 projection = Ogre::Plane(mydirection, myposition).projectVector(distance);
[1608]131
[2171]132        float projectionlength = projection.length();
[3049]133        if (projectionlength == 0)
134        {
135            if (myposition.dotProduct(otherposition) >= 0)
136                return orxonox::Vector2(0, 0);
137            else
138                return orxonox::Vector2(0, 1);
139        }
[6417]140
[3304]141        float cos_value = clamp<float>(myorthonormal.dotProduct(projection) / projectionlength, -1, 1);
142        float sin_value = sqrt( 1 - cos_value*cos_value );
[6417]143
[2171]144        if ((mydirection.crossProduct(myorthonormal)).dotProduct(distance) > 0)
[3304]145            return orxonox::Vector2( sin_value, cos_value );
[2171]146        else
[3304]147            return orxonox::Vector2( -sin_value, cos_value );
[2171]148    }
[1791]149
[2171]150    /**
151        @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).
152        @param myposition My position
153        @param mydirection My viewing direction
154        @param myorthonormal My orthonormalvector (pointing upwards through my head)
155        @param otherposition The position of the other object
156        @return The viewing direction
[1564]157
[2171]158        @example
159        If the other object is exactly in front of me, the function returns Vector2(0, 0).
160        If the other object is exactly at my left, the function returns Vector2(-0.5, 0).
161        If the other object is exactly at my right, the function returns Vector2(0.5, 0).
162        If the other object is only a bit at my right, the function still returns Vector2(0.01, 0).
163        If the other object is exactly above me, the function returns Vector2(0, 0.5).
164    */
165    orxonox::Vector2 get2DViewcoordinates(const orxonox::Vector3& myposition, const orxonox::Vector3& mydirection, const orxonox::Vector3& myorthonormal, const orxonox::Vector3& otherposition)
166    {
167        orxonox::Vector3 distance = otherposition - myposition;
[1564]168
[2171]169        // project difference vector on our plane
170        orxonox::Vector3 projection = Ogre::Plane(mydirection, myposition).projectVector(distance);
[1608]171
[2171]172        float projectionlength = projection.length();
[3049]173        if (projectionlength == 0)
174        {
175            if (myposition.dotProduct(otherposition) >= 0)
176                return orxonox::Vector2(0, 0);
177            else
178                return orxonox::Vector2(0, 1);
179        }
[3304]180        //float angle = acos(clamp<float>(myorthonormal.dotProduct(projection) / projectionlength, -1, 1));
[6417]181
[3304]182        float cos_value = clamp<float>(myorthonormal.dotProduct(projection) / projectionlength, -1, 1);
183        float sin_value = sqrt( 1 - cos_value*cos_value );
[1608]184
[2171]185        float distancelength = distance.length();
186        if (distancelength == 0) return orxonox::Vector2(0, 0);
[7184]187        float radius = acos(clamp<float>(mydirection.dotProduct(distance) / distancelength, -1, 1)) / math::pi;
[1566]188
[2171]189        if ((mydirection.crossProduct(myorthonormal)).dotProduct(distance) > 0)
[3304]190            return orxonox::Vector2( sin_value * radius, cos_value * radius);
[2171]191        else
[3304]192            return orxonox::Vector2( -sin_value * radius, cos_value * radius);
[2171]193    }
[1791]194
[2171]195    /**
196        @brief Returns the predicted position I have to aim at, if I want to hit a moving target with a moving projectile.
197        @param myposition My position
198        @param projectilespeed The speed of my projectile
199        @param targetposition The position of my target
200        @param targetvelocity The velocity of my target
201        @return The predicted position
[1566]202
[2171]203        The function predicts the position based on a linear velocity of the target. If the target changes speed or direction, the projectile will miss.
204    */
205    orxonox::Vector3 getPredictedPosition(const orxonox::Vector3& myposition, float projectilespeed, const orxonox::Vector3& targetposition, const orxonox::Vector3& targetvelocity)
206    {
207        float squaredProjectilespeed = projectilespeed * projectilespeed;
208        orxonox::Vector3 distance = targetposition - myposition;
209        float a = distance.squaredLength();
210        float b = 2 * (distance.x + distance.y + distance.z) * (targetvelocity.x + targetvelocity.y + targetvelocity.z);
211        float c = targetvelocity.squaredLength();
[1566]212
[2171]213        float temp = 4*squaredProjectilespeed*c + a*a - 4*b*c;
214        if (temp < 0)
215            return orxonox::Vector3::ZERO;
[1625]216
[2171]217        temp = sqrt(temp);
218        float time = (temp + a) / (2 * (squaredProjectilespeed - b));
219        return (targetposition + targetvelocity * time);
220    }
[1625]221
[2171]222    unsigned long getUniqueNumber()
223    {
224        static unsigned long aNumber = 135;
225        return aNumber++;
226    }
[2087]227
228
[2171]229    //////////////////////////
230    // Conversion functions //
231    //////////////////////////
[2087]232
[2171]233    // std::string to Vector2
234    bool ConverterFallback<std::string, orxonox::Vector2>::convert(orxonox::Vector2* output, const std::string& input)
[2087]235    {
[2171]236        size_t opening_parenthesis, closing_parenthesis = input.find(')');
237        if ((opening_parenthesis = input.find('(')) == std::string::npos)
238            opening_parenthesis = 0;
239        else
240            opening_parenthesis++;
[2087]241
[2171]242        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
243                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
244        if (tokens.size() >= 2)
245        {
[3196]246            if (!convertValue(&(output->x), tokens[0]))
[2171]247                return false;
[3196]248            if (!convertValue(&(output->y), tokens[1]))
[2171]249                return false;
250
251            return true;
252        }
253        return false;
[2087]254    }
255
[2171]256    // std::string to Vector3
257    bool ConverterFallback<std::string, orxonox::Vector3>::convert(orxonox::Vector3* output, const std::string& input)
[2087]258    {
[2171]259        size_t opening_parenthesis, closing_parenthesis = input.find(')');
260        if ((opening_parenthesis = input.find('(')) == std::string::npos)
261            opening_parenthesis = 0;
262        else
263            opening_parenthesis++;
[2087]264
[2171]265        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
266                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
267        if (tokens.size() >= 3)
268        {
[3196]269            if (!convertValue(&(output->x), tokens[0]))
[2171]270                return false;
[3196]271            if (!convertValue(&(output->y), tokens[1]))
[2171]272                return false;
[3196]273            if (!convertValue(&(output->z), tokens[2]))
[2171]274                return false;
275
276            return true;
277        }
278        return false;
[2087]279    }
280
[2171]281    // std::string to Vector4
282    bool ConverterFallback<std::string, orxonox::Vector4>::convert(orxonox::Vector4* output, const std::string& input)
[2087]283    {
[2171]284        size_t opening_parenthesis, closing_parenthesis = input.find(')');
285        if ((opening_parenthesis = input.find('(')) == std::string::npos)
286            opening_parenthesis = 0;
287        else
288            opening_parenthesis++;
[2087]289
[2171]290        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
291                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
292        if (tokens.size() >= 4)
293        {
[3196]294            if (!convertValue(&(output->x), tokens[0]))
[2171]295                return false;
[3196]296            if (!convertValue(&(output->y), tokens[1]))
[2171]297                return false;
[3196]298            if (!convertValue(&(output->z), tokens[2]))
[2171]299                return false;
[3196]300            if (!convertValue(&(output->w), tokens[3]))
[2171]301                return false;
302
303            return true;
304        }
305        return false;
[2087]306    }
307
[2171]308    // std::string to Quaternion
309    bool ConverterFallback<std::string, orxonox::Quaternion>::convert(orxonox::Quaternion* output, const std::string& input)
[2087]310    {
[2171]311        size_t opening_parenthesis, closing_parenthesis = input.find(')');
312        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[2087]313
[2171]314        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
315        if (tokens.size() >= 4)
316        {
[3196]317            if (!convertValue(&(output->w), tokens[0]))
[2171]318                return false;
[3196]319            if (!convertValue(&(output->x), tokens[1]))
[2171]320                return false;
[3196]321            if (!convertValue(&(output->y), tokens[2]))
[2171]322                return false;
[3196]323            if (!convertValue(&(output->z), tokens[3]))
[2171]324                return false;
325
326            return true;
327        }
328        return false;
[2087]329    }
330
[2171]331    // std::string to ColourValue
332    bool ConverterFallback<std::string, orxonox::ColourValue>::convert(orxonox::ColourValue* output, const std::string& input)
333    {
334        size_t opening_parenthesis, closing_parenthesis = input.find(')');
335        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
[2087]336
[2171]337        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
338        if (tokens.size() >= 3)
[2087]339        {
[3196]340            if (!convertValue(&(output->r), tokens[0]))
[2087]341                return false;
[3196]342            if (!convertValue(&(output->g), tokens[1]))
[2171]343                return false;
[3196]344            if (!convertValue(&(output->b), tokens[2]))
[2171]345                return false;
346            if (tokens.size() >= 4)
347            {
[3196]348                if (!convertValue(&(output->a), tokens[3]))
[2171]349                    return false;
350            }
351            else
352                output->a = 1.0;
353
354            return true;
[2087]355        }
[2171]356        return false;
[2087]357    }
358}
Note: See TracBrowser for help on using the repository browser.