Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/levelloader/src/lib/math/curve.cc @ 3557

Last change on this file since 3557 was 3499, checked in by chris, 20 years ago

orxonox/branches/levelloader: merged updated trunk structure into levelloader branch

File size: 10.1 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program 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 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: Patrick Boenzli
14
15   ADD: Patrick Boenzli           B-Spline
16
17
18   TODO:
19     local-Time implementation
20     NURBS
21     
22*/
23
24#include "curve.h"
25#include "matrix.h"
26#include "debug.h"
27
28#include <math.h>
29#include <stdio.h>
30
31/**
32   \brief adds a new Node to the bezier Curve
33   \param newNode a Vector to the position of the new node
34*/
35void Curve::addNode(const Vector& newNode)
36{
37  if (nodeCount != 0 )
38    {
39      currentNode = currentNode->next = new PathNode;
40    }
41  currentNode->position = newNode;
42  currentNode->next = 0;
43  currentNode->number = (++nodeCount);
44  this->rebuild();
45  return;
46}
47
48void Curve::addNode(const Vector& newNode, unsigned int insertPosition)
49{
50
51  if (this->nodeCount == 0 || insertPosition > this->nodeCount)
52    return addNode(newNode);
53
54  if (insertPosition == 0)
55    insertPosition = 1;
56
57  PathNode* insNode = new PathNode;
58
59  // relinking
60  PathNode* tmpNode = this->firstNode;
61  if (insertPosition > 1)
62    {
63      while (tmpNode->next->number != insertPosition)
64        tmpNode= tmpNode->next;
65      insNode->next = tmpNode->next;
66      tmpNode->next = insNode;
67    }
68  else
69    {
70      insNode->next = this->firstNode;
71      this->firstNode = insNode;
72    }
73  // renumbering
74  insNode->number = insertPosition;
75  tmpNode = insNode->next;
76  while (tmpNode)
77    {
78      tmpNode->number++;
79      tmpNode = tmpNode->next;
80    }
81
82    // finished
83  insNode->position = newNode;
84  ++nodeCount;
85  this->rebuild();
86  return;
87}
88
89/**
90   \brief Finds a Node by its Number, and returns its Position
91   \param nodeToFind the n'th node in the List of nodes
92   \returns A Vector to the Position of the Node.
93*/
94Vector Curve::getNode(unsigned int nodeToFind)
95{
96  if (nodeToFind > this->nodeCount || nodeToFind < 0)
97    return Vector(0,0,0);
98  PathNode* tmpNode = this->firstNode;
99  for (int i = 1; i < nodeToFind; i++)
100    tmpNode = tmpNode->next;
101  return tmpNode->position;
102}
103
104/**
105   \brief Outputs information about the state of this Curve
106*/
107void Curve::debug(void)
108{
109  printf("<<-------------------------------\n");
110  printf("Curve Information:\n");
111  printf("NodeCount: %d\n", this->nodeCount);
112  PathNode* tmpNode = this->firstNode;
113  while (tmpNode)
114    {
115      printf("node #%d: %f, %f, %f\n", tmpNode->number, tmpNode->position.x, tmpNode->position.y, tmpNode->position.z);
116      tmpNode = tmpNode->next;
117    }
118  printf("------------------------------->>\n");
119}
120
121
122///////////////////////////////////
123/// Bezier Curve //////////////////
124///////////////////////////////////
125
126/**
127   \brief Creates a new BezierCurve
128*/
129BezierCurve::BezierCurve (void)
130{
131  this->derivation = 0;
132  dirCurve = new BezierCurve(1);
133  this->init();
134}
135
136/**
137   \brief Creates a new BezierCurve-Derivation-Curve
138*/
139BezierCurve::BezierCurve (int derivation)
140{
141  this->derivation = derivation;
142  dirCurve=NULL;
143  this->init();
144}
145
146/**
147   \brief Deletes a BezierCurve.
148
149   It does this by freeing all the space taken over from the nodes
150*/
151BezierCurve::~BezierCurve(void)
152{
153  PathNode* tmpNode;
154  currentNode = firstNode;
155  while (tmpNode != 0)
156    {
157      tmpNode = currentNode;
158      currentNode = currentNode->next;
159      delete tmpNode;
160    }
161  if (dirCurve)
162    delete dirCurve;
163}
164
165/**
166   \brief Initializes a BezierCurve
167*/
168void BezierCurve::init(void)
169{
170  nodeCount = 0;
171  firstNode = new PathNode;
172  currentNode = firstNode;
173
174  firstNode->position = Vector (.0, .0, .0);
175  firstNode->number = 0;
176  firstNode->next = 0; // not sure if this really points to NULL!!
177
178  return;
179}
180
181/**
182   \brief Rebuilds a Curve
183*/
184void BezierCurve::rebuild(void)
185{
186  PathNode* tmpNode = firstNode;
187
188  // rebuilding the Curve itself
189  float k=0;
190  float n = nodeCount -1;
191  float binCoef = 1;
192  while(tmpNode)
193    {
194      tmpNode->factor = binCoef;
195      if (tmpNode =tmpNode->next)
196        {
197          binCoef *=(n-k)/(k+1);
198          ++k;
199        }
200    }
201
202  // rebuilding the Derivation curve
203  if(this->derivation <= 1)
204    {
205      tmpNode = firstNode;
206      delete dirCurve;
207      dirCurve = new BezierCurve(1);
208      while(tmpNode->next)
209        {
210          Vector tmpVector = (tmpNode->next->position)- (tmpNode->position);
211          tmpVector.x*=(float)nodeCount;
212          tmpVector.y*=(float)nodeCount;
213          tmpVector.z*=(float)nodeCount;
214          tmpVector.normalize();
215          this->dirCurve->addNode(tmpVector);
216          tmpNode = tmpNode->next;
217        }
218    }
219}
220
221/**
222   \brief calculates the Position on the curve
223   \param t The position on the Curve (0<=t<=1)
224   \return the Position on the Path
225*/
226Vector BezierCurve::calcPos(float t) 
227{
228  Vector ret = Vector(0.0,0.0,0.0);
229  if (this->nodeCount >= 3)
230    {
231      PathNode* tmpNode = this->firstNode;
232      double factor = pow(1.0-t,nodeCount-1);
233      while(tmpNode)
234        {
235          ret.x += tmpNode->factor * factor * tmpNode->position.x;
236          ret.y += tmpNode->factor * factor * tmpNode->position.y;
237          ret.z += tmpNode->factor * factor * tmpNode->position.z;
238          factor *= t/(1.0-t); // same as pow but much faster.
239         
240          tmpNode = tmpNode->next;
241        }
242    }
243  else if (nodeCount == 2)
244    {
245      ret = this->firstNode->position *(1.0-t);
246      ret = ret + this->firstNode->next->position * t;
247    }
248  else if (nodeCount == 1)
249    ret = this->firstNode->position;
250  return ret;
251}
252
253/**
254   \brief Calulates the direction of the Curve at time t.
255   \param The time at which to evaluate the curve.
256   \returns The vvaluated Vector.
257*/
258Vector BezierCurve::calcDir (float t)
259{
260  return dirCurve->calcPos(t);
261}
262
263Vector BezierCurve::calcAcc (float t)
264{
265  return dirCurve->dirCurve->calcPos(t);
266}
267
268/**
269   \brief Calculates the Quaternion needed for our rotations
270   \param t The time at which to evaluate the cuve.
271   \returns The evaluated Quaternion.
272*/
273Quaternion BezierCurve::calcQuat (float t)
274{
275  return Quaternion (calcDir(t), Vector(0,0,1));
276}
277
278
279/**
280  \brief returns the Position of the point calculated on the Curve
281  \return a Vector to the calculated position
282*/
283Vector BezierCurve::getPos(void) const
284{
285  return curvePoint;
286}
287
288
289
290///////////////////////////////////
291//// Uniform Point curve  /////////
292///////////////////////////////////
293/**
294   \brief Creates a new UPointCurve
295*/
296UPointCurve::UPointCurve (void)
297{
298  this->derivation = 0;
299  this->init();
300}
301
302/**
303   \brief Creates a new UPointCurve-Derivation-Curve of deriavation'th degree
304*/
305UPointCurve::UPointCurve (int derivation)
306{
307  this->derivation = derivation;
308  dirCurve=NULL;
309  this->init();
310}
311
312/**
313   \brief Deletes a UPointCurve.
314
315   It does this by freeing all the space taken over from the nodes
316*/
317UPointCurve::~UPointCurve(void)
318{
319  PathNode* tmpNode;
320  currentNode = firstNode;
321  while (tmpNode != 0)
322    {
323      tmpNode = currentNode;
324      currentNode = currentNode->next;
325      delete tmpNode;
326    }
327  if (dirCurve)
328    delete dirCurve;
329}
330
331/**
332   \brief Initializes a UPointCurve
333*/
334void UPointCurve::init(void)
335{
336  nodeCount = 0;
337  firstNode = new PathNode;
338  currentNode = firstNode;
339
340  firstNode->position = Vector (.0, .0, .0);
341  firstNode->number = 0;
342  firstNode->next = 0; // not sure if this really points to NULL!!
343
344  return;
345}
346
347/**
348   \brief Rebuilds a UPointCurve
349   
350   \todo very bad algorithm
351*/
352void UPointCurve::rebuild(void)
353{
354  // rebuilding the Curve itself
355  PathNode* tmpNode = this->firstNode;
356  int i=0;
357  Matrix xTmpMat = Matrix(this->nodeCount, this->nodeCount);
358  Matrix yTmpMat = Matrix(this->nodeCount, this->nodeCount);
359  Matrix zTmpMat = Matrix(this->nodeCount, this->nodeCount);
360  Matrix xValMat = Matrix(this->nodeCount, 3);
361  Matrix yValMat = Matrix(this->nodeCount, 3);
362  Matrix zValMat = Matrix(this->nodeCount, 3);
363  while(tmpNode)
364    {
365      Vector fac = Vector(1,1,1);
366      for (int j = 0; j < this->nodeCount; j++)
367        {
368          xTmpMat(i,j) = fac.x; fac.x *= (float)i/(float)this->nodeCount;//tmpNode->position.x;
369          yTmpMat(i,j) = fac.y; fac.y *= (float)i/(float)this->nodeCount;//tmpNode->position.y;
370          zTmpMat(i,j) = fac.z; fac.z *= (float)i/(float)this->nodeCount;//tmpNode->position.z;
371        }
372      xValMat(i,0) = tmpNode->position.x;
373      yValMat(i,0) = tmpNode->position.y;
374      zValMat(i,0) = tmpNode->position.z;
375      ++i;
376      tmpNode = tmpNode->next;
377    }
378  tmpNode = this->firstNode;
379  xValMat = xTmpMat.Inv() *= xValMat;
380  yValMat = yTmpMat.Inv() *= yValMat;
381  zValMat = zTmpMat.Inv() *= zValMat;
382  i = 0;
383  while(tmpNode)
384    {
385      tmpNode->vFactor.x = xValMat(i,0);
386      tmpNode->vFactor.y = yValMat(i,0);
387      tmpNode->vFactor.z = zValMat(i,0);
388
389      i++;
390      tmpNode = tmpNode->next;
391    }
392}
393
394/**
395   \brief calculates the Position on the curve
396   \param t The position on the Curve (0<=t<=1)
397   \return the Position on the Path
398*/
399Vector UPointCurve::calcPos(float t) 
400{
401  PathNode* tmpNode = firstNode;
402  Vector ret = Vector(0.0,0.0,0.0);
403  float factor = 1.0;
404  while(tmpNode)
405    {
406      ret.x += tmpNode->vFactor.x * factor;
407      ret.y += tmpNode->vFactor.y * factor;
408      ret.z += tmpNode->vFactor.z * factor;
409      factor *= t;
410
411      tmpNode = tmpNode->next;
412    }
413  return ret;
414}
415
416/**
417   \brief Calulates the direction of the Curve at time t.
418   \param The time at which to evaluate the curve.
419   \returns The vvaluated Vector.
420*/
421Vector UPointCurve::calcDir (float t)
422{
423  PathNode* tmpNode = firstNode;
424  Vector ret = Vector(0.0,0.0,0.0);
425  float factor = 1.0/t;
426  int k=0;
427  while(tmpNode)
428    {
429      ret.x += tmpNode->vFactor.x * factor *k;
430      ret.y += tmpNode->vFactor.y * factor *k;
431      ret.z += tmpNode->vFactor.z * factor *k;
432      factor *= t;
433      k++;
434      tmpNode = tmpNode->next;
435    }
436  ret.normalize();
437  return ret;
438}
439
440Vector UPointCurve::calcAcc (float t)
441{
442}
443
444/**
445   \brief Calculates the Quaternion needed for our rotations
446   \param t The time at which to evaluate the cuve.
447   \returns The evaluated Quaternion.
448*/
449Quaternion UPointCurve::calcQuat (float t)
450{
451  return Quaternion (calcDir(t), Vector(0,0,1));
452}
453
454
455/**
456  \brief returns the Position of the point calculated on the Curve
457  \return a Vector to the calculated position
458*/
459Vector UPointCurve::getPos(void) const
460{
461  return curvePoint;
462}
Note: See TracBrowser for help on using the repository browser.