Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core4/src/util/Math.cc @ 3225

Last change on this file since 3225 was 3196, checked in by rgrieder, 15 years ago

Merged pch branch back to trunk.

  • Property svn:eol-style set to native
File size: 13.6 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 angle = acos(clamp<float>(myorthonormal.dotProduct(projection) / projectionlength, -1, 1));
140
141        if ((mydirection.crossProduct(myorthonormal)).dotProduct(distance) > 0)
142            return orxonox::Vector2(sin(angle), cos(angle));
143        else
144            return orxonox::Vector2(-sin(angle), cos(angle));
145    }
146
147    /**
148        @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).
149        @param myposition My position
150        @param mydirection My viewing direction
151        @param myorthonormal My orthonormalvector (pointing upwards through my head)
152        @param otherposition The position of the other object
153        @return The viewing direction
154
155        @example
156        If the other object is exactly in front of me, the function returns Vector2(0, 0).
157        If the other object is exactly at my left, the function returns Vector2(-0.5, 0).
158        If the other object is exactly at my right, the function returns Vector2(0.5, 0).
159        If the other object is only a bit at my right, the function still returns Vector2(0.01, 0).
160        If the other object is exactly above me, the function returns Vector2(0, 0.5).
161    */
162    orxonox::Vector2 get2DViewcoordinates(const orxonox::Vector3& myposition, const orxonox::Vector3& mydirection, const orxonox::Vector3& myorthonormal, const orxonox::Vector3& otherposition)
163    {
164        orxonox::Vector3 distance = otherposition - myposition;
165
166        // project difference vector on our plane
167        orxonox::Vector3 projection = Ogre::Plane(mydirection, myposition).projectVector(distance);
168
169        float projectionlength = projection.length();
170        if (projectionlength == 0)
171        {
172            if (myposition.dotProduct(otherposition) >= 0)
173                return orxonox::Vector2(0, 0);
174            else
175                return orxonox::Vector2(0, 1);
176        }
177        float angle = acos(clamp<float>(myorthonormal.dotProduct(projection) / projectionlength, -1, 1));
178
179        float distancelength = distance.length();
180        if (distancelength == 0) return orxonox::Vector2(0, 0);
181        float radius = acos(clamp<float>(mydirection.dotProduct(distance) / distancelength, -1, 1)) / Ogre::Math::PI;
182
183        if ((mydirection.crossProduct(myorthonormal)).dotProduct(distance) > 0)
184            return orxonox::Vector2(sin(angle) * radius, cos(angle) * radius);
185        else
186            return orxonox::Vector2(-sin(angle) * radius, cos(angle) * radius);
187    }
188
189    /**
190        @brief Returns the predicted position I have to aim at, if I want to hit a moving target with a moving projectile.
191        @param myposition My position
192        @param projectilespeed The speed of my projectile
193        @param targetposition The position of my target
194        @param targetvelocity The velocity of my target
195        @return The predicted position
196
197        The function predicts the position based on a linear velocity of the target. If the target changes speed or direction, the projectile will miss.
198    */
199    orxonox::Vector3 getPredictedPosition(const orxonox::Vector3& myposition, float projectilespeed, const orxonox::Vector3& targetposition, const orxonox::Vector3& targetvelocity)
200    {
201        float squaredProjectilespeed = projectilespeed * projectilespeed;
202        orxonox::Vector3 distance = targetposition - myposition;
203        float a = distance.squaredLength();
204        float b = 2 * (distance.x + distance.y + distance.z) * (targetvelocity.x + targetvelocity.y + targetvelocity.z);
205        float c = targetvelocity.squaredLength();
206
207        float temp = 4*squaredProjectilespeed*c + a*a - 4*b*c;
208        if (temp < 0)
209            return orxonox::Vector3::ZERO;
210
211        temp = sqrt(temp);
212        float time = (temp + a) / (2 * (squaredProjectilespeed - b));
213        return (targetposition + targetvelocity * time);
214    }
215
216    unsigned long getUniqueNumber()
217    {
218        static unsigned long aNumber = 135;
219        return aNumber++;
220    }
221
222
223    //////////////////////////
224    // Conversion functions //
225    //////////////////////////
226
227    // std::string to Vector2
228    bool ConverterFallback<std::string, orxonox::Vector2>::convert(orxonox::Vector2* output, const std::string& input)
229    {
230        size_t opening_parenthesis, closing_parenthesis = input.find(')');
231        if ((opening_parenthesis = input.find('(')) == std::string::npos)
232            opening_parenthesis = 0;
233        else
234            opening_parenthesis++;
235
236        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
237                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
238        if (tokens.size() >= 2)
239        {
240            if (!convertValue(&(output->x), tokens[0]))
241                return false;
242            if (!convertValue(&(output->y), tokens[1]))
243                return false;
244
245            return true;
246        }
247        return false;
248    }
249
250    // std::string to Vector3
251    bool ConverterFallback<std::string, orxonox::Vector3>::convert(orxonox::Vector3* output, const std::string& input)
252    {
253        size_t opening_parenthesis, closing_parenthesis = input.find(')');
254        if ((opening_parenthesis = input.find('(')) == std::string::npos)
255            opening_parenthesis = 0;
256        else
257            opening_parenthesis++;
258
259        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
260                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
261        if (tokens.size() >= 3)
262        {
263            if (!convertValue(&(output->x), tokens[0]))
264                return false;
265            if (!convertValue(&(output->y), tokens[1]))
266                return false;
267            if (!convertValue(&(output->z), tokens[2]))
268                return false;
269
270            return true;
271        }
272        return false;
273    }
274
275    // std::string to Vector4
276    bool ConverterFallback<std::string, orxonox::Vector4>::convert(orxonox::Vector4* output, const std::string& input)
277    {
278        size_t opening_parenthesis, closing_parenthesis = input.find(')');
279        if ((opening_parenthesis = input.find('(')) == std::string::npos)
280            opening_parenthesis = 0;
281        else
282            opening_parenthesis++;
283
284        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis),
285                         ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
286        if (tokens.size() >= 4)
287        {
288            if (!convertValue(&(output->x), tokens[0]))
289                return false;
290            if (!convertValue(&(output->y), tokens[1]))
291                return false;
292            if (!convertValue(&(output->z), tokens[2]))
293                return false;
294            if (!convertValue(&(output->w), tokens[3]))
295                return false;
296
297            return true;
298        }
299        return false;
300    }
301
302    // std::string to Quaternion
303    bool ConverterFallback<std::string, orxonox::Quaternion>::convert(orxonox::Quaternion* output, const std::string& input)
304    {
305        size_t opening_parenthesis, closing_parenthesis = input.find(')');
306        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
307
308        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
309        if (tokens.size() >= 4)
310        {
311            if (!convertValue(&(output->w), tokens[0]))
312                return false;
313            if (!convertValue(&(output->x), tokens[1]))
314                return false;
315            if (!convertValue(&(output->y), tokens[2]))
316                return false;
317            if (!convertValue(&(output->z), tokens[3]))
318                return false;
319
320            return true;
321        }
322        return false;
323    }
324
325    // std::string to ColourValue
326    bool ConverterFallback<std::string, orxonox::ColourValue>::convert(orxonox::ColourValue* output, const std::string& input)
327    {
328        size_t opening_parenthesis, closing_parenthesis = input.find(')');
329        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
330
331        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
332        if (tokens.size() >= 3)
333        {
334            if (!convertValue(&(output->r), tokens[0]))
335                return false;
336            if (!convertValue(&(output->g), tokens[1]))
337                return false;
338            if (!convertValue(&(output->b), tokens[2]))
339                return false;
340            if (tokens.size() >= 4)
341            {
342                if (!convertValue(&(output->a), tokens[3]))
343                    return false;
344            }
345            else
346                output->a = 1.0;
347
348            return true;
349        }
350        return false;
351    }
352}
Note: See TracBrowser for help on using the repository browser.