Curve.h (72505B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #ifndef __MATH_CURVE_H__ 30 #define __MATH_CURVE_H__ 31 32 /* 33 =============================================================================== 34 35 Curve base template. 36 37 =============================================================================== 38 */ 39 40 template< class type > 41 class idCurve { 42 public: 43 idCurve(); 44 virtual ~idCurve(); 45 46 virtual int AddValue( const float time, const type &value ); 47 virtual void RemoveIndex( const int index ) { values.RemoveIndex(index); times.RemoveIndex(index); changed = true; } 48 virtual void Clear() { values.Clear(); times.Clear(); currentIndex = -1; changed = true; } 49 50 virtual type GetCurrentValue( const float time ) const; 51 virtual type GetCurrentFirstDerivative( const float time ) const; 52 virtual type GetCurrentSecondDerivative( const float time ) const; 53 54 virtual bool IsDone( const float time ) const; 55 56 int GetNumValues() const { return values.Num(); } 57 void SetValue( const int index, const type &value ) { values[index] = value; changed = true; } 58 type GetValue( const int index ) const { return values[index]; } 59 type * GetValueAddress( const int index ) { return &values[index]; } 60 float GetTime( const int index ) const { return times[index]; } 61 62 float GetLengthForTime( const float time ) const; 63 float GetTimeForLength( const float length, const float epsilon = 0.1f ) const; 64 float GetLengthBetweenKnots( const int i0, const int i1 ) const; 65 66 void MakeUniform( const float totalTime ); 67 void SetConstantSpeed( const float totalTime ); 68 void ShiftTime( const float deltaTime ); 69 void Translate( const type &translation ); 70 71 protected: 72 73 idList<float> times; // knots 74 idList<type> values; // knot values 75 76 mutable int currentIndex; // cached index for fast lookup 77 mutable bool changed; // set whenever the curve changes 78 79 int IndexForTime( const float time ) const; 80 float TimeForIndex( const int index ) const; 81 type ValueForIndex( const int index ) const; 82 83 float GetSpeed( const float time ) const; 84 float RombergIntegral( const float t0, const float t1, const int order ) const; 85 }; 86 87 /* 88 ==================== 89 idCurve::idCurve 90 ==================== 91 */ 92 template< class type > 93 ID_INLINE idCurve<type>::idCurve() { 94 currentIndex = -1; 95 changed = false; 96 } 97 98 /* 99 ==================== 100 idCurve::~idCurve 101 ==================== 102 */ 103 template< class type > 104 ID_INLINE idCurve<type>::~idCurve() { 105 } 106 107 /* 108 ==================== 109 idCurve::AddValue 110 111 add a timed/value pair to the spline 112 returns the index to the inserted pair 113 ==================== 114 */ 115 template< class type > 116 ID_INLINE int idCurve<type>::AddValue( const float time, const type &value ) { 117 int i; 118 119 i = IndexForTime( time ); 120 times.Insert( time, i ); 121 values.Insert( value, i ); 122 changed = true; 123 return i; 124 } 125 126 /* 127 ==================== 128 idCurve::GetCurrentValue 129 130 get the value for the given time 131 ==================== 132 */ 133 template< class type > 134 ID_INLINE type idCurve<type>::GetCurrentValue( const float time ) const { 135 int i; 136 137 i = IndexForTime( time ); 138 if ( i >= values.Num() ) { 139 return values[values.Num() - 1]; 140 } else { 141 return values[i]; 142 } 143 } 144 145 /* 146 ==================== 147 idCurve::GetCurrentFirstDerivative 148 149 get the first derivative for the given time 150 ==================== 151 */ 152 template< class type > 153 ID_INLINE type idCurve<type>::GetCurrentFirstDerivative( const float time ) const { 154 return ( values[0] - values[0] ); //-V501 155 } 156 157 /* 158 ==================== 159 idCurve::GetCurrentSecondDerivative 160 161 get the second derivative for the given time 162 ==================== 163 */ 164 template< class type > 165 ID_INLINE type idCurve<type>::GetCurrentSecondDerivative( const float time ) const { 166 return ( values[0] - values[0] ); //-V501 167 } 168 169 /* 170 ==================== 171 idCurve::IsDone 172 ==================== 173 */ 174 template< class type > 175 ID_INLINE bool idCurve<type>::IsDone( const float time ) const { 176 return ( time >= times[ times.Num() - 1 ] ); 177 } 178 179 /* 180 ==================== 181 idCurve::GetSpeed 182 ==================== 183 */ 184 template< class type > 185 ID_INLINE float idCurve<type>::GetSpeed( const float time ) const { 186 int i; 187 float speed; 188 type value; 189 190 value = GetCurrentFirstDerivative( time ); 191 for ( speed = 0.0f, i = 0; i < value.GetDimension(); i++ ) { 192 speed += value[i] * value[i]; 193 } 194 return idMath::Sqrt( speed ); 195 } 196 197 /* 198 ==================== 199 idCurve::RombergIntegral 200 ==================== 201 */ 202 template< class type > 203 ID_INLINE float idCurve<type>::RombergIntegral( const float t0, const float t1, const int order ) const { 204 int i, j, k, m, n; 205 float sum, delta; 206 float *temp[2]; 207 208 temp[0] = (float *) _alloca16( order * sizeof( float ) ); 209 temp[1] = (float *) _alloca16( order * sizeof( float ) ); 210 211 delta = t1 - t0; 212 temp[0][0] = 0.5f * delta * ( GetSpeed( t0 ) + GetSpeed( t1 ) ); 213 214 for ( i = 2, m = 1; i <= order; i++, m *= 2, delta *= 0.5f ) { 215 216 // approximate using the trapezoid rule 217 sum = 0.0f; 218 for ( j = 1; j <= m; j++ ) { 219 sum += GetSpeed( t0 + delta * ( j - 0.5f ) ); 220 } 221 222 // Richardson extrapolation 223 temp[1][0] = 0.5f * ( temp[0][0] + delta * sum ); 224 for ( k = 1, n = 4; k < i; k++, n *= 4 ) { 225 temp[1][k] = ( n * temp[1][k-1] - temp[0][k-1] ) / ( n - 1 ); 226 } 227 228 for ( j = 0; j < i; j++ ) { 229 temp[0][j] = temp[1][j]; 230 } 231 } 232 return temp[0][order-1]; 233 } 234 235 /* 236 ==================== 237 idCurve::GetLengthBetweenKnots 238 ==================== 239 */ 240 template< class type > 241 ID_INLINE float idCurve<type>::GetLengthBetweenKnots( const int i0, const int i1 ) const { 242 float length = 0.0f; 243 for ( int i = i0; i < i1; i++ ) { 244 length += RombergIntegral( times[i], times[i+1], 5 ); 245 } 246 return length; 247 } 248 249 /* 250 ==================== 251 idCurve::GetLengthForTime 252 ==================== 253 */ 254 template< class type > 255 ID_INLINE float idCurve<type>::GetLengthForTime( const float time ) const { 256 float length = 0.0f; 257 int index = IndexForTime( time ); 258 for ( int i = 0; i < index; i++ ) { 259 length += RombergIntegral( times[i], times[i+1], 5 ); 260 } 261 length += RombergIntegral( times[index], time, 5 ); 262 return length; 263 } 264 265 /* 266 ==================== 267 idCurve::GetTimeForLength 268 ==================== 269 */ 270 template< class type > 271 ID_INLINE float idCurve<type>::GetTimeForLength( const float length, const float epsilon ) const { 272 int i, index; 273 float *accumLength, totalLength, len0, len1, t, diff; 274 275 if ( length <= 0.0f ) { 276 return times[0]; 277 } 278 279 accumLength = (float *) _alloca16( values.Num() * sizeof( float ) ); 280 totalLength = 0.0f; 281 for ( index = 0; index < values.Num() - 1; index++ ) { 282 totalLength += GetLengthBetweenKnots( index, index + 1 ); 283 accumLength[index] = totalLength; 284 if ( length < accumLength[index] ) { 285 break; 286 } 287 } 288 289 if ( index >= values.Num() - 1 ) { 290 return times[times.Num() - 1]; 291 } 292 293 if ( index == 0 ) { 294 len0 = length; 295 len1 = accumLength[0]; 296 } else { 297 len0 = length - accumLength[index-1]; 298 len1 = accumLength[index] - accumLength[index-1]; 299 } 300 301 // invert the arc length integral using Newton's method 302 t = ( times[index+1] - times[index] ) * len0 / len1; 303 for ( i = 0; i < 32; i++ ) { 304 diff = RombergIntegral( times[index], times[index] + t, 5 ) - len0; 305 if ( idMath::Fabs( diff ) <= epsilon ) { 306 return times[index] + t; 307 } 308 t -= diff / GetSpeed( times[index] + t ); 309 } 310 return times[index] + t; 311 } 312 313 /* 314 ==================== 315 idCurve::MakeUniform 316 ==================== 317 */ 318 template< class type > 319 ID_INLINE void idCurve<type>::MakeUniform( const float totalTime ) { 320 int i, n; 321 322 n = times.Num() - 1; 323 for ( i = 0; i <= n; i++ ) { 324 times[i] = i * totalTime / n; 325 } 326 changed = true; 327 } 328 329 /* 330 ==================== 331 idCurve::SetConstantSpeed 332 ==================== 333 */ 334 template< class type > 335 ID_INLINE void idCurve<type>::SetConstantSpeed( const float totalTime ) { 336 int i, j; 337 float *length, totalLength, scale, t; 338 339 length = (float *) _alloca16( values.Num() * sizeof( float ) ); 340 totalLength = 0.0f; 341 for ( i = 0; i < values.Num() - 1; i++ ) { 342 length[i] = GetLengthBetweenKnots( i, i + 1 ); 343 totalLength += length[i]; 344 } 345 scale = totalTime / totalLength; 346 for ( t = 0.0f, i = 0; i < times.Num() - 1; i++ ) { 347 times[i] = t; 348 t += scale * length[i]; 349 } 350 times[times.Num() - 1] = totalTime; 351 changed = true; 352 } 353 354 /* 355 ==================== 356 idCurve::ShiftTime 357 ==================== 358 */ 359 template< class type > 360 ID_INLINE void idCurve<type>::ShiftTime( const float deltaTime ) { 361 for ( int i = 0; i < times.Num(); i++ ) { 362 times[i] += deltaTime; 363 } 364 changed = true; 365 } 366 367 /* 368 ==================== 369 idCurve::Translate 370 ==================== 371 */ 372 template< class type > 373 ID_INLINE void idCurve<type>::Translate( const type &translation ) { 374 for ( int i = 0; i < values.Num(); i++ ) { 375 values[i] += translation; 376 } 377 changed = true; 378 } 379 380 /* 381 ==================== 382 idCurve::IndexForTime 383 384 find the index for the first time greater than or equal to the given time 385 ==================== 386 */ 387 template< class type > 388 ID_INLINE int idCurve<type>::IndexForTime( const float time ) const { 389 int len, mid, offset, res; 390 391 if ( currentIndex >= 0 && currentIndex <= times.Num() ) { 392 // use the cached index if it is still valid 393 if ( currentIndex == 0 ) { 394 if ( time <= times[currentIndex] ) { 395 return currentIndex; 396 } 397 } else if ( currentIndex == times.Num() ) { 398 if ( time > times[currentIndex-1] ) { 399 return currentIndex; 400 } 401 } else if ( time > times[currentIndex-1] && time <= times[currentIndex] ) { 402 return currentIndex; 403 } else if ( time > times[currentIndex] && ( currentIndex+1 == times.Num() || time <= times[currentIndex+1] ) ) { 404 // use the next index 405 currentIndex++; 406 return currentIndex; 407 } 408 } 409 410 // use binary search to find the index for the given time 411 len = times.Num(); 412 mid = len; 413 offset = 0; 414 res = 0; 415 while( mid > 0 ) { 416 mid = len >> 1; 417 if ( time == times[offset+mid] ) { 418 return offset+mid; 419 } else if ( time > times[offset+mid] ) { 420 offset += mid; 421 len -= mid; 422 res = 1; 423 } else { 424 len -= mid; 425 res = 0; 426 } 427 } 428 currentIndex = offset+res; 429 return currentIndex; 430 } 431 432 /* 433 ==================== 434 idCurve::ValueForIndex 435 436 get the value for the given time 437 ==================== 438 */ 439 template< class type > 440 ID_INLINE type idCurve<type>::ValueForIndex( const int index ) const { 441 int n = values.Num()-1; 442 443 if ( index < 0 ) { 444 return values[0] + index * ( values[1] - values[0] ); 445 } else if ( index > n ) { 446 return values[n] + ( index - n ) * ( values[n] - values[n-1] ); 447 } 448 return values[index]; 449 } 450 451 /* 452 ==================== 453 idCurve::TimeForIndex 454 455 get the value for the given time 456 ==================== 457 */ 458 template< class type > 459 ID_INLINE float idCurve<type>::TimeForIndex( const int index ) const { 460 int n = times.Num()-1; 461 462 if ( index < 0 ) { 463 return times[0] + index * ( times[1] - times[0] ); 464 } else if ( index > n ) { 465 return times[n] + ( index - n ) * ( times[n] - times[n-1] ); 466 } 467 return times[index]; 468 } 469 470 471 /* 472 =============================================================================== 473 474 Bezier Curve template. 475 The degree of the polynomial equals the number of knots minus one. 476 477 =============================================================================== 478 */ 479 480 template< class type > 481 class idCurve_Bezier : public idCurve<type> { 482 public: 483 idCurve_Bezier(); 484 485 virtual type GetCurrentValue( const float time ) const; 486 virtual type GetCurrentFirstDerivative( const float time ) const; 487 virtual type GetCurrentSecondDerivative( const float time ) const; 488 489 protected: 490 void Basis( const int order, const float t, float *bvals ) const; 491 void BasisFirstDerivative( const int order, const float t, float *bvals ) const; 492 void BasisSecondDerivative( const int order, const float t, float *bvals ) const; 493 }; 494 495 /* 496 ==================== 497 idCurve_Bezier::idCurve_Bezier 498 ==================== 499 */ 500 template< class type > 501 ID_INLINE idCurve_Bezier<type>::idCurve_Bezier() { 502 } 503 504 /* 505 ==================== 506 idCurve_Bezier::GetCurrentValue 507 508 get the value for the given time 509 ==================== 510 */ 511 template< class type > 512 ID_INLINE type idCurve_Bezier<type>::GetCurrentValue( const float time ) const { 513 int i; 514 float *bvals; 515 type v; 516 517 bvals = (float *) _alloca16( this->values.Num() * sizeof( float ) ); 518 519 Basis( this->values.Num(), time, bvals ); 520 v = bvals[0] * this->values[0]; 521 for ( i = 1; i < this->values.Num(); i++ ) { 522 v += bvals[i] * this->values[i]; 523 } 524 return v; 525 } 526 527 /* 528 ==================== 529 idCurve_Bezier::GetCurrentFirstDerivative 530 531 get the first derivative for the given time 532 ==================== 533 */ 534 template< class type > 535 ID_INLINE type idCurve_Bezier<type>::GetCurrentFirstDerivative( const float time ) const { 536 int i; 537 float *bvals, d; 538 type v; 539 540 bvals = (float *) _alloca16( this->values.Num() * sizeof( float ) ); 541 542 BasisFirstDerivative( this->values.Num(), time, bvals ); 543 v = bvals[0] * this->values[0]; 544 for ( i = 1; i < this->values.Num(); i++ ) { 545 v += bvals[i] * this->values[i]; 546 } 547 d = ( this->times[this->times.Num()-1] - this->times[0] ); 548 return ( (float) (this->values.Num()-1) / d ) * v; 549 } 550 551 /* 552 ==================== 553 idCurve_Bezier::GetCurrentSecondDerivative 554 555 get the second derivative for the given time 556 ==================== 557 */ 558 template< class type > 559 ID_INLINE type idCurve_Bezier<type>::GetCurrentSecondDerivative( const float time ) const { 560 int i; 561 float *bvals, d; 562 type v; 563 564 bvals = (float *) _alloca16( this->values.Num() * sizeof( float ) ); 565 566 BasisSecondDerivative( this->values.Num(), time, bvals ); 567 v = bvals[0] * this->values[0]; 568 for ( i = 1; i < this->values.Num(); i++ ) { 569 v += bvals[i] * this->values[i]; 570 } 571 d = ( this->times[this->times.Num()-1] - this->times[0] ); 572 return ( (float) (this->values.Num()-2) * (this->values.Num()-1) / ( d * d ) ) * v; 573 } 574 575 /* 576 ==================== 577 idCurve_Bezier::Basis 578 579 bezier basis functions 580 ==================== 581 */ 582 template< class type > 583 ID_INLINE void idCurve_Bezier<type>::Basis( const int order, const float t, float *bvals ) const { 584 int i, j, d; 585 float *c, c1, c2, s, o, ps, po; 586 587 bvals[0] = 1.0f; 588 d = order - 1; 589 if ( d <= 0 ) { 590 return; 591 } 592 593 c = (float *) _alloca16( (d+1) * sizeof( float ) ); 594 s = (float) ( t - this->times[0] ) / ( this->times[this->times.Num()-1] - this->times[0] ); 595 o = 1.0f - s; 596 ps = s; 597 po = o; 598 599 for ( i = 1; i < d; i++ ) { 600 c[i] = 1.0f; 601 } 602 for ( i = 1; i < d; i++ ) { 603 c[i-1] = 0.0f; 604 c1 = c[i]; 605 c[i] = 1.0f; 606 for ( j = i+1; j <= d; j++ ) { 607 c2 = c[j]; 608 c[j] = c1 + c[j-1]; 609 c1 = c2; 610 } 611 bvals[i] = c[d] * ps; 612 ps *= s; 613 } 614 for ( i = d-1; i >= 0; i-- ) { 615 bvals[i] *= po; 616 po *= o; 617 } 618 bvals[d] = ps; 619 } 620 621 /* 622 ==================== 623 idCurve_Bezier::BasisFirstDerivative 624 625 first derivative of bezier basis functions 626 ==================== 627 */ 628 template< class type > 629 ID_INLINE void idCurve_Bezier<type>::BasisFirstDerivative( const int order, const float t, float *bvals ) const { 630 int i; 631 632 Basis( order-1, t, bvals+1 ); 633 bvals[0] = 0.0f; 634 for ( i = 0; i < order-1; i++ ) { 635 bvals[i] -= bvals[i+1]; 636 } 637 } 638 639 /* 640 ==================== 641 idCurve_Bezier::BasisSecondDerivative 642 643 second derivative of bezier basis functions 644 ==================== 645 */ 646 template< class type > 647 ID_INLINE void idCurve_Bezier<type>::BasisSecondDerivative( const int order, const float t, float *bvals ) const { 648 int i; 649 650 BasisFirstDerivative( order-1, t, bvals+1 ); 651 bvals[0] = 0.0f; 652 for ( i = 0; i < order-1; i++ ) { 653 bvals[i] -= bvals[i+1]; 654 } 655 } 656 657 658 /* 659 =============================================================================== 660 661 Quadratic Bezier Curve template. 662 Should always have exactly three knots. 663 664 =============================================================================== 665 */ 666 667 template< class type > 668 class idCurve_QuadraticBezier : public idCurve<type> { 669 670 public: 671 idCurve_QuadraticBezier(); 672 673 virtual type GetCurrentValue( const float time ) const; 674 virtual type GetCurrentFirstDerivative( const float time ) const; 675 virtual type GetCurrentSecondDerivative( const float time ) const; 676 677 protected: 678 void Basis( const float t, float *bvals ) const; 679 void BasisFirstDerivative( const float t, float *bvals ) const; 680 void BasisSecondDerivative( const float t, float *bvals ) const; 681 }; 682 683 /* 684 ==================== 685 idCurve_QuadraticBezier::idCurve_QuadraticBezier 686 ==================== 687 */ 688 template< class type > 689 ID_INLINE idCurve_QuadraticBezier<type>::idCurve_QuadraticBezier() { 690 } 691 692 693 /* 694 ==================== 695 idCurve_QuadraticBezier::GetCurrentValue 696 697 get the value for the given time 698 ==================== 699 */ 700 template< class type > 701 ID_INLINE type idCurve_QuadraticBezier<type>::GetCurrentValue( const float time ) const { 702 float bvals[3]; 703 assert( this->values.Num() == 3 ); 704 Basis( time, bvals ); 705 return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] ); 706 } 707 708 /* 709 ==================== 710 idCurve_QuadraticBezier::GetCurrentFirstDerivative 711 712 get the first derivative for the given time 713 ==================== 714 */ 715 template< class type > 716 ID_INLINE type idCurve_QuadraticBezier<type>::GetCurrentFirstDerivative( const float time ) const { 717 float bvals[3], d; 718 assert( this->values.Num() == 3 ); 719 BasisFirstDerivative( time, bvals ); 720 d = ( this->times[2] - this->times[0] ); 721 return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] ) / d; 722 } 723 724 /* 725 ==================== 726 idCurve_QuadraticBezier::GetCurrentSecondDerivative 727 728 get the second derivative for the given time 729 ==================== 730 */ 731 template< class type > 732 ID_INLINE type idCurve_QuadraticBezier<type>::GetCurrentSecondDerivative( const float time ) const { 733 float bvals[3], d; 734 assert( this->values.Num() == 3 ); 735 BasisSecondDerivative( time, bvals ); 736 d = ( this->times[2] - this->times[0] ); 737 return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] ) / ( d * d ); 738 } 739 740 /* 741 ==================== 742 idCurve_QuadraticBezier::Basis 743 744 quadratic bezier basis functions 745 ==================== 746 */ 747 template< class type > 748 ID_INLINE void idCurve_QuadraticBezier<type>::Basis( const float t, float *bvals ) const { 749 float s1 = (float) ( t - this->times[0] ) / ( this->times[2] - this->times[0] ); 750 float s2 = s1 * s1; 751 bvals[0] = s2 - 2.0f * s1 + 1.0f; 752 bvals[1] = -2.0f * s2 + 2.0f * s1; 753 bvals[2] = s2; 754 } 755 756 /* 757 ==================== 758 idCurve_QuadraticBezier::BasisFirstDerivative 759 760 first derivative of quadratic bezier basis functions 761 ==================== 762 */ 763 template< class type > 764 ID_INLINE void idCurve_QuadraticBezier<type>::BasisFirstDerivative( const float t, float *bvals ) const { 765 float s1 = (float) ( t - this->times[0] ) / ( this->times[2] - this->times[0] ); 766 bvals[0] = 2.0f * s1 - 2.0f; 767 bvals[1] = -4.0f * s1 + 2.0f; 768 bvals[2] = 2.0f * s1; 769 } 770 771 /* 772 ==================== 773 idCurve_QuadraticBezier::BasisSecondDerivative 774 775 second derivative of quadratic bezier basis functions 776 ==================== 777 */ 778 template< class type > 779 ID_INLINE void idCurve_QuadraticBezier<type>::BasisSecondDerivative( const float t, float *bvals ) const { 780 float s1 = (float) ( t - this->times[0] ) / ( this->times[2] - this->times[0] ); 781 bvals[0] = 2.0f; 782 bvals[1] = -4.0f; 783 bvals[2] = 2.0f; 784 } 785 786 787 /* 788 =============================================================================== 789 790 Cubic Bezier Curve template. 791 Should always have exactly four knots. 792 793 =============================================================================== 794 */ 795 796 template< class type > 797 class idCurve_CubicBezier : public idCurve<type> { 798 799 public: 800 idCurve_CubicBezier(); 801 802 virtual type GetCurrentValue( const float time ) const; 803 virtual type GetCurrentFirstDerivative( const float time ) const; 804 virtual type GetCurrentSecondDerivative( const float time ) const; 805 806 protected: 807 void Basis( const float t, float *bvals ) const; 808 void BasisFirstDerivative( const float t, float *bvals ) const; 809 void BasisSecondDerivative( const float t, float *bvals ) const; 810 }; 811 812 /* 813 ==================== 814 idCurve_CubicBezier::idCurve_CubicBezier 815 ==================== 816 */ 817 template< class type > 818 ID_INLINE idCurve_CubicBezier<type>::idCurve_CubicBezier() { 819 } 820 821 822 /* 823 ==================== 824 idCurve_CubicBezier::GetCurrentValue 825 826 get the value for the given time 827 ==================== 828 */ 829 template< class type > 830 ID_INLINE type idCurve_CubicBezier<type>::GetCurrentValue( const float time ) const { 831 float bvals[4]; 832 assert( this->values.Num() == 4 ); 833 Basis( time, bvals ); 834 return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] + bvals[3] * this->values[3] ); 835 } 836 837 /* 838 ==================== 839 idCurve_CubicBezier::GetCurrentFirstDerivative 840 841 get the first derivative for the given time 842 ==================== 843 */ 844 template< class type > 845 ID_INLINE type idCurve_CubicBezier<type>::GetCurrentFirstDerivative( const float time ) const { 846 float bvals[4], d; 847 assert( this->values.Num() == 4 ); 848 BasisFirstDerivative( time, bvals ); 849 d = ( this->times[3] - this->times[0] ); 850 return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] + bvals[3] * this->values[3] ) / d; 851 } 852 853 /* 854 ==================== 855 idCurve_CubicBezier::GetCurrentSecondDerivative 856 857 get the second derivative for the given time 858 ==================== 859 */ 860 template< class type > 861 ID_INLINE type idCurve_CubicBezier<type>::GetCurrentSecondDerivative( const float time ) const { 862 float bvals[4], d; 863 assert( this->values.Num() == 4 ); 864 BasisSecondDerivative( time, bvals ); 865 d = ( this->times[3] - this->times[0] ); 866 return ( bvals[0] * this->values[0] + bvals[1] * this->values[1] + bvals[2] * this->values[2] + bvals[3] * this->values[3] ) / ( d * d ); 867 } 868 869 /* 870 ==================== 871 idCurve_CubicBezier::Basis 872 873 cubic bezier basis functions 874 ==================== 875 */ 876 template< class type > 877 ID_INLINE void idCurve_CubicBezier<type>::Basis( const float t, float *bvals ) const { 878 float s1 = (float) ( t - this->times[0] ) / ( this->times[3] - this->times[0] ); 879 float s2 = s1 * s1; 880 float s3 = s2 * s1; 881 bvals[0] = -s3 + 3.0f * s2 - 3.0f * s1 + 1.0f; 882 bvals[1] = 3.0f * s3 - 6.0f * s2 + 3.0f * s1; 883 bvals[2] = -3.0f * s3 + 3.0f * s2; 884 bvals[3] = s3; 885 } 886 887 /* 888 ==================== 889 idCurve_CubicBezier::BasisFirstDerivative 890 891 first derivative of cubic bezier basis functions 892 ==================== 893 */ 894 template< class type > 895 ID_INLINE void idCurve_CubicBezier<type>::BasisFirstDerivative( const float t, float *bvals ) const { 896 float s1 = (float) ( t - this->times[0] ) / ( this->times[3] - this->times[0] ); 897 float s2 = s1 * s1; 898 bvals[0] = -3.0f * s2 + 6.0f * s1 - 3.0f; 899 bvals[1] = 9.0f * s2 - 12.0f * s1 + 3.0f; 900 bvals[2] = -9.0f * s2 + 6.0f * s1; 901 bvals[3] = 3.0f * s2; 902 } 903 904 /* 905 ==================== 906 idCurve_CubicBezier::BasisSecondDerivative 907 908 second derivative of cubic bezier basis functions 909 ==================== 910 */ 911 template< class type > 912 ID_INLINE void idCurve_CubicBezier<type>::BasisSecondDerivative( const float t, float *bvals ) const { 913 float s1 = (float) ( t - this->times[0] ) / ( this->times[3] - this->times[0] ); 914 bvals[0] = -6.0f * s1 + 6.0f; 915 bvals[1] = 18.0f * s1 - 12.0f; 916 bvals[2] = -18.0f * s1 + 6.0f; 917 bvals[3] = 6.0f * s1; 918 } 919 920 921 /* 922 =============================================================================== 923 924 Spline base template. 925 926 =============================================================================== 927 */ 928 929 template< class type > 930 class idCurve_Spline : public idCurve<type> { 931 932 public: 933 enum boundary_t { BT_FREE, BT_CLAMPED, BT_CLOSED }; 934 935 idCurve_Spline(); 936 937 virtual bool IsDone( const float time ) const; 938 939 virtual void SetBoundaryType( const boundary_t bt ) { boundaryType = bt; this->changed = true; } 940 virtual boundary_t GetBoundaryType() const { return boundaryType; } 941 942 virtual void SetCloseTime( const float t ) { closeTime = t; this->changed = true; } 943 virtual float GetCloseTime() { return boundaryType == BT_CLOSED ? closeTime : 0.0f; } 944 945 protected: 946 boundary_t boundaryType; 947 float closeTime; 948 949 type ValueForIndex( const int index ) const; 950 float TimeForIndex( const int index ) const; 951 float ClampedTime( const float t ) const; 952 }; 953 954 /* 955 ==================== 956 idCurve_Spline::idCurve_Spline 957 ==================== 958 */ 959 template< class type > 960 ID_INLINE idCurve_Spline<type>::idCurve_Spline() { 961 boundaryType = BT_FREE; 962 closeTime = 0.0f; 963 } 964 965 /* 966 ==================== 967 idCurve_Spline::ValueForIndex 968 969 get the value for the given time 970 ==================== 971 */ 972 template< class type > 973 ID_INLINE type idCurve_Spline<type>::ValueForIndex( const int index ) const { 974 int n = this->values.Num()-1; 975 976 if ( index < 0 ) { 977 if ( boundaryType == BT_CLOSED ) { 978 return this->values[ this->values.Num() + index % this->values.Num() ]; 979 } 980 else { 981 return this->values[0] + index * ( this->values[1] - this->values[0] ); 982 } 983 } 984 else if ( index > n ) { 985 if ( boundaryType == BT_CLOSED ) { 986 return this->values[ index % this->values.Num() ]; 987 } 988 else { 989 return this->values[n] + ( index - n ) * ( this->values[n] - this->values[n-1] ); 990 } 991 } 992 return this->values[index]; 993 } 994 995 /* 996 ==================== 997 idCurve_Spline::TimeForIndex 998 999 get the value for the given time 1000 ==================== 1001 */ 1002 template< class type > 1003 ID_INLINE float idCurve_Spline<type>::TimeForIndex( const int index ) const { 1004 int n = this->times.Num()-1; 1005 1006 if ( index < 0 ) { 1007 if ( boundaryType == BT_CLOSED ) { 1008 return ( index / this->times.Num() ) * ( this->times[n] + closeTime ) - ( this->times[n] + closeTime - this->times[this->times.Num() + index % this->times.Num()] ); 1009 } 1010 else { 1011 return this->times[0] + index * ( this->times[1] - this->times[0] ); 1012 } 1013 } 1014 else if ( index > n ) { 1015 if ( boundaryType == BT_CLOSED ) { 1016 return ( index / this->times.Num() ) * ( this->times[n] + closeTime ) + this->times[index % this->times.Num()]; 1017 } 1018 else { 1019 return this->times[n] + ( index - n ) * ( this->times[n] - this->times[n-1] ); 1020 } 1021 } 1022 return this->times[index]; 1023 } 1024 1025 /* 1026 ==================== 1027 idCurve_Spline::ClampedTime 1028 1029 return the clamped time based on the boundary type 1030 ==================== 1031 */ 1032 template< class type > 1033 ID_INLINE float idCurve_Spline<type>::ClampedTime( const float t ) const { 1034 if ( boundaryType == BT_CLAMPED ) { 1035 if ( t < this->times[0] ) { 1036 return this->times[0]; 1037 } 1038 else if ( t >= this->times[this->times.Num()-1] ) { 1039 return this->times[this->times.Num()-1]; 1040 } 1041 } 1042 return t; 1043 } 1044 1045 /* 1046 ==================== 1047 idCurve_Spline::IsDone 1048 ==================== 1049 */ 1050 template< class type > 1051 ID_INLINE bool idCurve_Spline<type>::IsDone( const float time ) const { 1052 return ( boundaryType != BT_CLOSED && time >= this->times[ this->times.Num() - 1 ] ); 1053 } 1054 1055 1056 /* 1057 =============================================================================== 1058 1059 Cubic Interpolating Spline template. 1060 The curve goes through all the knots. 1061 1062 =============================================================================== 1063 */ 1064 1065 template< class type > 1066 class idCurve_NaturalCubicSpline : public idCurve_Spline<type> { 1067 public: 1068 idCurve_NaturalCubicSpline(); 1069 1070 virtual void Clear() { idCurve_Spline<type>::Clear(); this->values.Clear(); b.Clear(); c.Clear(); d.Clear(); } 1071 1072 virtual type GetCurrentValue( const float time ) const; 1073 virtual type GetCurrentFirstDerivative( const float time ) const; 1074 virtual type GetCurrentSecondDerivative( const float time ) const; 1075 1076 protected: 1077 mutable idList<type>b; 1078 mutable idList<type>c; 1079 mutable idList<type>d; 1080 1081 void Setup() const; 1082 void SetupFree() const; 1083 void SetupClamped() const; 1084 void SetupClosed() const; 1085 }; 1086 1087 /* 1088 ==================== 1089 idCurve_NaturalCubicSpline::idCurve_NaturalCubicSpline 1090 ==================== 1091 */ 1092 template< class type > 1093 ID_INLINE idCurve_NaturalCubicSpline<type>::idCurve_NaturalCubicSpline() { 1094 } 1095 1096 /* 1097 ==================== 1098 idCurve_NaturalCubicSpline::GetCurrentValue 1099 1100 get the value for the given time 1101 ==================== 1102 */ 1103 template< class type > 1104 ID_INLINE type idCurve_NaturalCubicSpline<type>::GetCurrentValue( const float time ) const { 1105 float clampedTime = this->ClampedTime( time ); 1106 int i = this->IndexForTime( clampedTime ); 1107 float s = time - this->TimeForIndex( i ); 1108 Setup(); 1109 return ( this->values[i] + s * ( b[i] + s * ( c[i] + s * d[i] ) ) ); 1110 } 1111 1112 /* 1113 ==================== 1114 idCurve_NaturalCubicSpline::GetCurrentFirstDerivative 1115 1116 get the first derivative for the given time 1117 ==================== 1118 */ 1119 template< class type > 1120 ID_INLINE type idCurve_NaturalCubicSpline<type>::GetCurrentFirstDerivative( const float time ) const { 1121 float clampedTime = this->ClampedTime( time ); 1122 int i = this->IndexForTime( clampedTime ); 1123 float s = time - this->TimeForIndex( i ); 1124 Setup(); 1125 return ( b[i] + s * ( 2.0f * c[i] + 3.0f * s * d[i] ) ); 1126 } 1127 1128 /* 1129 ==================== 1130 idCurve_NaturalCubicSpline::GetCurrentSecondDerivative 1131 1132 get the second derivative for the given time 1133 ==================== 1134 */ 1135 template< class type > 1136 ID_INLINE type idCurve_NaturalCubicSpline<type>::GetCurrentSecondDerivative( const float time ) const { 1137 float clampedTime = this->ClampedTime( time ); 1138 int i = this->IndexForTime( clampedTime ); 1139 float s = time - this->TimeForIndex( i ); 1140 Setup(); 1141 return ( 2.0f * c[i] + 6.0f * s * d[i] ); 1142 } 1143 1144 /* 1145 ==================== 1146 idCurve_NaturalCubicSpline::Setup 1147 ==================== 1148 */ 1149 template< class type > 1150 ID_INLINE void idCurve_NaturalCubicSpline<type>::Setup() const { 1151 if ( this->changed ) { 1152 switch( this->boundaryType ) { 1153 case idCurve_Spline<type>::BT_FREE: SetupFree(); break; 1154 case idCurve_Spline<type>::BT_CLAMPED: SetupClamped(); break; 1155 case idCurve_Spline<type>::BT_CLOSED: SetupClosed(); break; 1156 } 1157 this->changed = false; 1158 } 1159 } 1160 1161 /* 1162 ==================== 1163 idCurve_NaturalCubicSpline::SetupFree 1164 ==================== 1165 */ 1166 template< class type > 1167 ID_INLINE void idCurve_NaturalCubicSpline<type>::SetupFree() const { 1168 int i; 1169 float inv; 1170 float *d0, *d1, *beta, *gamma; 1171 type *alpha, *delta; 1172 1173 d0 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) ); 1174 d1 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) ); 1175 alpha = (type *) _alloca16( ( this->values.Num() - 1 ) * sizeof( type ) ); 1176 beta = (float *) _alloca16( this->values.Num() * sizeof( float ) ); 1177 gamma = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) ); 1178 delta = (type *) _alloca16( this->values.Num() * sizeof( type ) ); 1179 1180 for ( i = 0; i < this->values.Num() - 1; i++ ) { 1181 d0[i] = this->times[i+1] - this->times[i]; 1182 } 1183 1184 for ( i = 1; i < this->values.Num() - 1; i++ ) { 1185 d1[i] = this->times[i+1] - this->times[i-1]; 1186 } 1187 1188 for ( i = 1; i < this->values.Num() - 1; i++ ) { 1189 type sum = 3.0f * ( d0[i-1] * this->values[i+1] - d1[i] * this->values[i] + d0[i] * this->values[i-1] ); 1190 inv = 1.0f / ( d0[i-1] * d0[i] ); 1191 alpha[i] = inv * sum; 1192 } 1193 1194 beta[0] = 1.0f; 1195 gamma[0] = 0.0f; 1196 delta[0] = this->values[0] - this->values[0]; //-V501 1197 1198 for ( i = 1; i < this->values.Num() - 1; i++ ) { 1199 beta[i] = 2.0f * d1[i] - d0[i-1] * gamma[i-1]; 1200 inv = 1.0f / beta[i]; 1201 gamma[i] = inv * d0[i]; 1202 delta[i] = inv * ( alpha[i] - d0[i-1] * delta[i-1] ); 1203 } 1204 beta[this->values.Num() - 1] = 1.0f; 1205 delta[this->values.Num() - 1] = this->values[0] - this->values[0]; //-V501 1206 1207 b.AssureSize( this->values.Num() ); 1208 c.AssureSize( this->values.Num() ); 1209 d.AssureSize( this->values.Num() ); 1210 1211 c[this->values.Num() - 1] = this->values[0] - this->values[0]; //-V501 1212 1213 for ( i = this->values.Num() - 2; i >= 0; i-- ) { 1214 c[i] = delta[i] - gamma[i] * c[i+1]; 1215 inv = 1.0f / d0[i]; 1216 b[i] = inv * ( this->values[i+1] - this->values[i] ) - ( 1.0f / 3.0f ) * d0[i] * ( c[i+1] + 2.0f * c[i] ); 1217 d[i] = ( 1.0f / 3.0f ) * inv * ( c[i+1] - c[i] ); 1218 } 1219 } 1220 1221 /* 1222 ==================== 1223 idCurve_NaturalCubicSpline::SetupClamped 1224 ==================== 1225 */ 1226 template< class type > 1227 ID_INLINE void idCurve_NaturalCubicSpline<type>::SetupClamped() const { 1228 int i; 1229 float inv; 1230 float *d0, *d1, *beta, *gamma; 1231 type *alpha, *delta; 1232 1233 d0 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) ); 1234 d1 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) ); 1235 alpha = (type *) _alloca16( ( this->values.Num() - 1 ) * sizeof( type ) ); 1236 beta = (float *) _alloca16( this->values.Num() * sizeof( float ) ); 1237 gamma = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) ); 1238 delta = (type *) _alloca16( this->values.Num() * sizeof( type ) ); 1239 1240 for ( i = 0; i < this->values.Num() - 1; i++ ) { 1241 d0[i] = this->times[i+1] - this->times[i]; 1242 } 1243 1244 for ( i = 1; i < this->values.Num() - 1; i++ ) { 1245 d1[i] = this->times[i+1] - this->times[i-1]; 1246 } 1247 1248 inv = 1.0f / d0[0]; 1249 alpha[0] = 3.0f * ( inv - 1.0f ) * ( this->values[1] - this->values[0] ); 1250 inv = 1.0f / d0[this->values.Num() - 2]; 1251 alpha[this->values.Num() - 1] = 3.0f * ( 1.0f - inv ) * ( this->values[this->values.Num() - 1] - this->values[this->values.Num() - 2] ); 1252 1253 for ( i = 1; i < this->values.Num() - 1; i++ ) { 1254 type sum = 3.0f * ( d0[i-1] * this->values[i+1] - d1[i] * this->values[i] + d0[i] * this->values[i-1] ); 1255 inv = 1.0f / ( d0[i-1] * d0[i] ); 1256 alpha[i] = inv * sum; 1257 } 1258 1259 beta[0] = 2.0f * d0[0]; 1260 gamma[0] = 0.5f; 1261 inv = 1.0f / beta[0]; 1262 delta[0] = inv * alpha[0]; 1263 1264 for ( i = 1; i < this->values.Num() - 1; i++ ) { 1265 beta[i] = 2.0f * d1[i] - d0[i-1] * gamma[i-1]; 1266 inv = 1.0f / beta[i]; 1267 gamma[i] = inv * d0[i]; 1268 delta[i] = inv * ( alpha[i] - d0[i-1] * delta[i-1] ); 1269 } 1270 1271 beta[this->values.Num() - 1] = d0[this->values.Num() - 2] * ( 2.0f - gamma[this->values.Num() - 2] ); 1272 inv = 1.0f / beta[this->values.Num() - 1]; 1273 delta[this->values.Num() - 1] = inv * ( alpha[this->values.Num() - 1] - d0[this->values.Num() - 2] * delta[this->values.Num() - 2] ); 1274 1275 b.AssureSize( this->values.Num() ); 1276 c.AssureSize( this->values.Num() ); 1277 d.AssureSize( this->values.Num() ); 1278 1279 c[this->values.Num() - 1] = delta[this->values.Num() - 1]; 1280 1281 for ( i = this->values.Num() - 2; i >= 0; i-- ) { 1282 c[i] = delta[i] - gamma[i] * c[i+1]; 1283 inv = 1.0f / d0[i]; 1284 b[i] = inv * ( this->values[i+1] - this->values[i] ) - ( 1.0f / 3.0f ) * d0[i]* ( c[i+1] + 2.0f * c[i] ); 1285 d[i] = ( 1.0f / 3.0f ) * inv * ( c[i+1] - c[i] ); 1286 } 1287 } 1288 1289 /* 1290 ==================== 1291 idCurve_NaturalCubicSpline::SetupClosed 1292 ==================== 1293 */ 1294 template< class type > 1295 ID_INLINE void idCurve_NaturalCubicSpline<type>::SetupClosed() const { 1296 int i, j; 1297 float c0, c1; 1298 float *d0; 1299 idMatX mat; 1300 idVecX x; 1301 1302 d0 = (float *) _alloca16( ( this->values.Num() - 1 ) * sizeof( float ) ); 1303 x.SetData( this->values.Num(), VECX_ALLOCA( this->values.Num() ) ); 1304 mat.SetData( this->values.Num(), this->values.Num(), MATX_ALLOCA( this->values.Num() * this->values.Num() ) ); 1305 1306 b.AssureSize( this->values.Num() ); 1307 c.AssureSize( this->values.Num() ); 1308 d.AssureSize( this->values.Num() ); 1309 1310 for ( i = 0; i < this->values.Num() - 1; i++ ) { 1311 d0[i] = this->times[i+1] - this->times[i]; 1312 } 1313 1314 // matrix of system 1315 mat[0][0] = 1.0f; 1316 mat[0][this->values.Num() - 1] = -1.0f; 1317 for ( i = 1; i <= this->values.Num() - 2; i++ ) { 1318 mat[i][i-1] = d0[i-1]; 1319 mat[i][i ] = 2.0f * ( d0[i-1] + d0[i] ); 1320 mat[i][i+1] = d0[i]; 1321 } 1322 mat[this->values.Num() - 1][this->values.Num() - 2] = d0[this->values.Num() - 2]; 1323 mat[this->values.Num() - 1][0] = 2.0f * ( d0[this->values.Num() - 2] + d0[0] ); 1324 mat[this->values.Num() - 1][1] = d0[0]; 1325 1326 // right-hand side 1327 c[0].Zero(); 1328 for ( i = 1; i <= this->values.Num() - 2; i++ ) { 1329 c0 = 1.0f / d0[i]; 1330 c1 = 1.0f / d0[i-1]; 1331 c[i] = 3.0f * ( c0 * ( this->values[i + 1] - this->values[i] ) - c1 * ( this->values[i] - this->values[i - 1] ) ); 1332 } 1333 c0 = 1.0f / d0[0]; 1334 c1 = 1.0f / d0[this->values.Num() - 2]; 1335 c[this->values.Num() - 1] = 3.0f * ( c0 * ( this->values[1] - this->values[0] ) - c1 * ( this->values[0] - this->values[this->values.Num() - 2] ) ); 1336 1337 // solve system for each dimension 1338 mat.LU_Factor( NULL ); 1339 for ( i = 0; i < this->values[0].GetDimension(); i++ ) { 1340 for ( j = 0; j < this->values.Num(); j++ ) { 1341 x[j] = c[j][i]; 1342 } 1343 mat.LU_Solve( x, x, NULL ); 1344 for ( j = 0; j < this->values.Num(); j++ ) { 1345 c[j][i] = x[j]; 1346 } 1347 } 1348 1349 for ( i = 0; i < this->values.Num() - 1; i++ ) { 1350 c0 = 1.0f / d0[i]; 1351 b[i] = c0 * ( this->values[i + 1] - this->values[i] ) - ( 1.0f / 3.0f ) * ( c[i+1] + 2.0f * c[i] ) * d0[i]; 1352 d[i] = ( 1.0f / 3.0f ) * c0 * ( c[i + 1] - c[i] ); 1353 } 1354 } 1355 1356 1357 /* 1358 =============================================================================== 1359 1360 Uniform Cubic Interpolating Spline template. 1361 The curve goes through all the knots. 1362 1363 =============================================================================== 1364 */ 1365 1366 template< class type > 1367 class idCurve_CatmullRomSpline : public idCurve_Spline<type> { 1368 1369 public: 1370 idCurve_CatmullRomSpline(); 1371 1372 virtual type GetCurrentValue( const float time ) const; 1373 virtual type GetCurrentFirstDerivative( const float time ) const; 1374 virtual type GetCurrentSecondDerivative( const float time ) const; 1375 1376 protected: 1377 void Basis( const int index, const float t, float *bvals ) const; 1378 void BasisFirstDerivative( const int index, const float t, float *bvals ) const; 1379 void BasisSecondDerivative( const int index, const float t, float *bvals ) const; 1380 }; 1381 1382 /* 1383 ==================== 1384 idCurve_CatmullRomSpline::idCurve_CatmullRomSpline 1385 ==================== 1386 */ 1387 template< class type > 1388 ID_INLINE idCurve_CatmullRomSpline<type>::idCurve_CatmullRomSpline() { 1389 } 1390 1391 /* 1392 ==================== 1393 idCurve_CatmullRomSpline::GetCurrentValue 1394 1395 get the value for the given time 1396 ==================== 1397 */ 1398 template< class type > 1399 ID_INLINE type idCurve_CatmullRomSpline<type>::GetCurrentValue( const float time ) const { 1400 int i, j, k; 1401 float bvals[4], clampedTime; 1402 type v; 1403 1404 if ( this->times.Num() == 1 ) { 1405 return this->values[0]; 1406 } 1407 1408 clampedTime = this->ClampedTime( time ); 1409 i = this->IndexForTime( clampedTime ); 1410 Basis( i-1, clampedTime, bvals ); 1411 v = this->values[0] - this->values[0]; //-V501 1412 for ( j = 0; j < 4; j++ ) { 1413 k = i + j - 2; 1414 v += bvals[j] * this->ValueForIndex( k ); 1415 } 1416 return v; 1417 } 1418 1419 /* 1420 ==================== 1421 idCurve_CatmullRomSpline::GetCurrentFirstDerivative 1422 1423 get the first derivative for the given time 1424 ==================== 1425 */ 1426 template< class type > 1427 ID_INLINE type idCurve_CatmullRomSpline<type>::GetCurrentFirstDerivative( const float time ) const { 1428 int i, j, k; 1429 float bvals[4], d, clampedTime; 1430 type v; 1431 1432 if ( this->times.Num() == 1 ) { 1433 return ( this->values[0] - this->values[0] ); //-V501 1434 } 1435 1436 clampedTime = this->ClampedTime( time ); 1437 i = this->IndexForTime( clampedTime ); 1438 BasisFirstDerivative( i-1, clampedTime, bvals ); 1439 v = this->values[0] - this->values[0]; //-V501 1440 for ( j = 0; j < 4; j++ ) { 1441 k = i + j - 2; 1442 v += bvals[j] * this->ValueForIndex( k ); 1443 } 1444 d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) ); 1445 return v / d; 1446 } 1447 1448 /* 1449 ==================== 1450 idCurve_CatmullRomSpline::GetCurrentSecondDerivative 1451 1452 get the second derivative for the given time 1453 ==================== 1454 */ 1455 template< class type > 1456 ID_INLINE type idCurve_CatmullRomSpline<type>::GetCurrentSecondDerivative( const float time ) const { 1457 int i, j, k; 1458 float bvals[4], d, clampedTime; 1459 type v; 1460 1461 if ( this->times.Num() == 1 ) { 1462 return ( this->values[0] - this->values[0] ); //-V501 1463 } 1464 1465 clampedTime = this->ClampedTime( time ); 1466 i = this->IndexForTime( clampedTime ); 1467 BasisSecondDerivative( i-1, clampedTime, bvals ); 1468 v = this->values[0] - this->values[0]; //-V501 1469 for ( j = 0; j < 4; j++ ) { 1470 k = i + j - 2; 1471 v += bvals[j] * this->ValueForIndex( k ); 1472 } 1473 d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) ); 1474 return v / ( d * d ); 1475 } 1476 1477 /* 1478 ==================== 1479 idCurve_CatmullRomSpline::Basis 1480 1481 spline basis functions 1482 ==================== 1483 */ 1484 template< class type > 1485 ID_INLINE void idCurve_CatmullRomSpline<type>::Basis( const int index, const float t, float *bvals ) const { 1486 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 1487 bvals[0] = ( ( -s + 2.0f ) * s - 1.0f ) * s * 0.5f; // -0.5f s * s * s + s * s - 0.5f * s 1488 bvals[1] = ( ( ( 3.0f * s - 5.0f ) * s ) * s + 2.0f ) * 0.5f; // 1.5f * s * s * s - 2.5f * s * s + 1.0f 1489 bvals[2] = ( ( -3.0f * s + 4.0f ) * s + 1.0f ) * s * 0.5f; // -1.5f * s * s * s - 2.0f * s * s + 0.5f s 1490 bvals[3] = ( ( s - 1.0f ) * s * s ) * 0.5f; // 0.5f * s * s * s - 0.5f * s * s 1491 } 1492 1493 /* 1494 ==================== 1495 idCurve_CatmullRomSpline::BasisFirstDerivative 1496 1497 first derivative of spline basis functions 1498 ==================== 1499 */ 1500 template< class type > 1501 ID_INLINE void idCurve_CatmullRomSpline<type>::BasisFirstDerivative( const int index, const float t, float *bvals ) const { 1502 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 1503 bvals[0] = ( -1.5f * s + 2.0f ) * s - 0.5f; // -1.5f * s * s + 2.0f * s - 0.5f 1504 bvals[1] = ( 4.5f * s - 5.0f ) * s; // 4.5f * s * s - 5.0f * s 1505 bvals[2] = ( -4.5 * s + 4.0f ) * s + 0.5f; // -4.5 * s * s + 4.0f * s + 0.5f 1506 bvals[3] = 1.5f * s * s - s; // 1.5f * s * s - s 1507 } 1508 1509 /* 1510 ==================== 1511 idCurve_CatmullRomSpline::BasisSecondDerivative 1512 1513 second derivative of spline basis functions 1514 ==================== 1515 */ 1516 template< class type > 1517 ID_INLINE void idCurve_CatmullRomSpline<type>::BasisSecondDerivative( const int index, const float t, float *bvals ) const { 1518 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 1519 bvals[0] = -3.0f * s + 2.0f; 1520 bvals[1] = 9.0f * s - 5.0f; 1521 bvals[2] = -9.0f * s + 4.0f; 1522 bvals[3] = 3.0f * s - 1.0f; 1523 } 1524 1525 1526 /* 1527 =============================================================================== 1528 1529 Cubic Interpolating Spline template. 1530 The curve goes through all the knots. 1531 The curve becomes the Catmull-Rom spline if the tension, 1532 continuity and bias are all set to zero. 1533 1534 =============================================================================== 1535 */ 1536 1537 template< class type > 1538 class idCurve_KochanekBartelsSpline : public idCurve_Spline<type> { 1539 1540 public: 1541 idCurve_KochanekBartelsSpline(); 1542 1543 virtual int AddValue( const float time, const type &value ); 1544 virtual int AddValue( const float time, const type &value, const float tension, const float continuity, const float bias ); 1545 virtual void RemoveIndex( const int index ) { this->values.RemoveIndex(index); this->times.RemoveIndex(index); tension.RemoveIndex(index); continuity.RemoveIndex(index); bias.RemoveIndex(index); } 1546 virtual void Clear() { this->values.Clear(); this->times.Clear(); tension.Clear(); continuity.Clear(); bias.Clear(); this->currentIndex = -1; } 1547 1548 virtual type GetCurrentValue( const float time ) const; 1549 virtual type GetCurrentFirstDerivative( const float time ) const; 1550 virtual type GetCurrentSecondDerivative( const float time ) const; 1551 1552 protected: 1553 idList<float> tension; 1554 idList<float> continuity; 1555 idList<float> bias; 1556 1557 void TangentsForIndex( const int index, type &t0, type &t1 ) const; 1558 1559 void Basis( const int index, const float t, float *bvals ) const; 1560 void BasisFirstDerivative( const int index, const float t, float *bvals ) const; 1561 void BasisSecondDerivative( const int index, const float t, float *bvals ) const; 1562 }; 1563 1564 /* 1565 ==================== 1566 idCurve_KochanekBartelsSpline::idCurve_KochanekBartelsSpline 1567 ==================== 1568 */ 1569 template< class type > 1570 ID_INLINE idCurve_KochanekBartelsSpline<type>::idCurve_KochanekBartelsSpline() { 1571 } 1572 1573 /* 1574 ==================== 1575 idCurve_KochanekBartelsSpline::AddValue 1576 1577 add a timed/value pair to the spline 1578 returns the index to the inserted pair 1579 ==================== 1580 */ 1581 template< class type > 1582 ID_INLINE int idCurve_KochanekBartelsSpline<type>::AddValue( const float time, const type &value ) { 1583 int i; 1584 1585 i = this->IndexForTime( time ); 1586 this->times.Insert( time, i ); 1587 this->values.Insert( value, i ); 1588 tension.Insert( 0.0f, i ); 1589 continuity.Insert( 0.0f, i ); 1590 bias.Insert( 0.0f, i ); 1591 return i; 1592 } 1593 1594 /* 1595 ==================== 1596 idCurve_KochanekBartelsSpline::AddValue 1597 1598 add a timed/value pair to the spline 1599 returns the index to the inserted pair 1600 ==================== 1601 */ 1602 template< class type > 1603 ID_INLINE int idCurve_KochanekBartelsSpline<type>::AddValue( const float time, const type &value, const float tension, const float continuity, const float bias ) { 1604 int i; 1605 1606 i = this->IndexForTime( time ); 1607 this->times.Insert( time, i ); 1608 this->values.Insert( value, i ); 1609 this->tension.Insert( tension, i ); 1610 this->continuity.Insert( continuity, i ); 1611 this->bias.Insert( bias, i ); 1612 return i; 1613 } 1614 1615 /* 1616 ==================== 1617 idCurve_KochanekBartelsSpline::GetCurrentValue 1618 1619 get the value for the given time 1620 ==================== 1621 */ 1622 template< class type > 1623 ID_INLINE type idCurve_KochanekBartelsSpline<type>::GetCurrentValue( const float time ) const { 1624 int i; 1625 float bvals[4], clampedTime; 1626 type v, t0, t1; 1627 1628 if ( this->times.Num() == 1 ) { 1629 return this->values[0]; 1630 } 1631 1632 clampedTime = this->ClampedTime( time ); 1633 i = this->IndexForTime( clampedTime ); 1634 TangentsForIndex( i - 1, t0, t1 ); 1635 Basis( i - 1, clampedTime, bvals ); 1636 v = bvals[0] * this->ValueForIndex( i - 1 ); 1637 v += bvals[1] * this->ValueForIndex( i ); 1638 v += bvals[2] * t0; 1639 v += bvals[3] * t1; 1640 return v; 1641 } 1642 1643 /* 1644 ==================== 1645 idCurve_KochanekBartelsSpline::GetCurrentFirstDerivative 1646 1647 get the first derivative for the given time 1648 ==================== 1649 */ 1650 template< class type > 1651 ID_INLINE type idCurve_KochanekBartelsSpline<type>::GetCurrentFirstDerivative( const float time ) const { 1652 int i; 1653 float bvals[4], d, clampedTime; 1654 type v, t0, t1; 1655 1656 if ( this->times.Num() == 1 ) { 1657 return ( this->values[0] - this->values[0] ); //-V501 1658 } 1659 1660 clampedTime = this->ClampedTime( time ); 1661 i = this->IndexForTime( clampedTime ); 1662 TangentsForIndex( i - 1, t0, t1 ); 1663 BasisFirstDerivative( i - 1, clampedTime, bvals ); 1664 v = bvals[0] * this->ValueForIndex( i - 1 ); 1665 v += bvals[1] * this->ValueForIndex( i ); 1666 v += bvals[2] * t0; 1667 v += bvals[3] * t1; 1668 d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) ); 1669 return v / d; 1670 } 1671 1672 /* 1673 ==================== 1674 idCurve_KochanekBartelsSpline::GetCurrentSecondDerivative 1675 1676 get the second derivative for the given time 1677 ==================== 1678 */ 1679 template< class type > 1680 ID_INLINE type idCurve_KochanekBartelsSpline<type>::GetCurrentSecondDerivative( const float time ) const { 1681 int i; 1682 float bvals[4], d, clampedTime; 1683 type v, t0, t1; 1684 1685 if ( this->times.Num() == 1 ) { 1686 return ( this->values[0] - this->values[0] ); //-V501 1687 } 1688 1689 clampedTime = this->ClampedTime( time ); 1690 i = this->IndexForTime( clampedTime ); 1691 TangentsForIndex( i - 1, t0, t1 ); 1692 BasisSecondDerivative( i - 1, clampedTime, bvals ); 1693 v = bvals[0] * this->ValueForIndex( i - 1 ); 1694 v += bvals[1] * this->ValueForIndex( i ); 1695 v += bvals[2] * t0; 1696 v += bvals[3] * t1; 1697 d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) ); 1698 return v / ( d * d ); 1699 } 1700 1701 /* 1702 ==================== 1703 idCurve_KochanekBartelsSpline::TangentsForIndex 1704 ==================== 1705 */ 1706 template< class type > 1707 ID_INLINE void idCurve_KochanekBartelsSpline<type>::TangentsForIndex( const int index, type &t0, type &t1 ) const { 1708 float dt, omt, omc, opc, omb, opb, adj, s0, s1; 1709 type delta; 1710 1711 delta = this->ValueForIndex( index + 1 ) - this->ValueForIndex( index ); 1712 dt = this->TimeForIndex( index + 1 ) - this->TimeForIndex( index ); 1713 1714 omt = 1.0f - tension[index]; 1715 omc = 1.0f - continuity[index]; 1716 opc = 1.0f + continuity[index]; 1717 omb = 1.0f - bias[index]; 1718 opb = 1.0f + bias[index]; 1719 adj = 2.0f * dt / ( this->TimeForIndex( index + 1 ) - this->TimeForIndex( index - 1 ) ); 1720 s0 = 0.5f * adj * omt * opc * opb; 1721 s1 = 0.5f * adj * omt * omc * omb; 1722 1723 // outgoing tangent at first point 1724 t0 = s1 * delta + s0 * ( this->ValueForIndex( index ) - this->ValueForIndex( index - 1 ) ); 1725 1726 omt = 1.0f - tension[index + 1]; 1727 omc = 1.0f - continuity[index + 1]; 1728 opc = 1.0f + continuity[index + 1]; 1729 omb = 1.0f - bias[index + 1]; 1730 opb = 1.0f + bias[index + 1]; 1731 adj = 2.0f * dt / ( this->TimeForIndex( index + 2 ) - this->TimeForIndex( index ) ); 1732 s0 = 0.5f * adj * omt * omc * opb; 1733 s1 = 0.5f * adj * omt * opc * omb; 1734 1735 // incoming tangent at second point 1736 t1 = s1 * ( this->ValueForIndex( index + 2 ) - this->ValueForIndex( index + 1 ) ) + s0 * delta; 1737 } 1738 1739 /* 1740 ==================== 1741 idCurve_KochanekBartelsSpline::Basis 1742 1743 spline basis functions 1744 ==================== 1745 */ 1746 template< class type > 1747 ID_INLINE void idCurve_KochanekBartelsSpline<type>::Basis( const int index, const float t, float *bvals ) const { 1748 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 1749 bvals[0] = ( ( 2.0f * s - 3.0f ) * s ) * s + 1.0f; // 2.0f * s * s * s - 3.0f * s * s + 1.0f 1750 bvals[1] = ( ( -2.0f * s + 3.0f ) * s ) * s; // -2.0f * s * s * s + 3.0f * s * s 1751 bvals[2] = ( ( s - 2.0f ) * s ) * s + s; // s * s * s - 2.0f * s * s + s 1752 bvals[3] = ( ( s - 1.0f ) * s ) * s; // s * s * s - s * s 1753 } 1754 1755 /* 1756 ==================== 1757 idCurve_KochanekBartelsSpline::BasisFirstDerivative 1758 1759 first derivative of spline basis functions 1760 ==================== 1761 */ 1762 template< class type > 1763 ID_INLINE void idCurve_KochanekBartelsSpline<type>::BasisFirstDerivative( const int index, const float t, float *bvals ) const { 1764 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 1765 bvals[0] = ( 6.0f * s - 6.0f ) * s; // 6.0f * s * s - 6.0f * s 1766 bvals[1] = ( -6.0f * s + 6.0f ) * s; // -6.0f * s * s + 6.0f * s 1767 bvals[2] = ( 3.0f * s - 4.0f ) * s + 1.0f; // 3.0f * s * s - 4.0f * s + 1.0f 1768 bvals[3] = ( 3.0f * s - 2.0f ) * s; // 3.0f * s * s - 2.0f * s 1769 } 1770 1771 /* 1772 ==================== 1773 idCurve_KochanekBartelsSpline::BasisSecondDerivative 1774 1775 second derivative of spline basis functions 1776 ==================== 1777 */ 1778 template< class type > 1779 ID_INLINE void idCurve_KochanekBartelsSpline<type>::BasisSecondDerivative( const int index, const float t, float *bvals ) const { 1780 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 1781 bvals[0] = 12.0f * s - 6.0f; 1782 bvals[1] = -12.0f * s + 6.0f; 1783 bvals[2] = 6.0f * s - 4.0f; 1784 bvals[3] = 6.0f * s - 2.0f; 1785 } 1786 1787 1788 /* 1789 =============================================================================== 1790 1791 B-Spline base template. Uses recursive definition and is slow. 1792 Use idCurve_UniformCubicBSpline or idCurve_NonUniformBSpline instead. 1793 1794 =============================================================================== 1795 */ 1796 1797 template< class type > 1798 class idCurve_BSpline : public idCurve_Spline<type> { 1799 1800 public: 1801 idCurve_BSpline(); 1802 1803 virtual int GetOrder() const { return order; } 1804 virtual void SetOrder( const int i ) { assert( i > 0 && i < 10 ); order = i; } 1805 1806 virtual type GetCurrentValue( const float time ) const; 1807 virtual type GetCurrentFirstDerivative( const float time ) const; 1808 virtual type GetCurrentSecondDerivative( const float time ) const; 1809 1810 protected: 1811 int order; 1812 1813 float Basis( const int index, const int order, const float t ) const; 1814 float BasisFirstDerivative( const int index, const int order, const float t ) const; 1815 float BasisSecondDerivative( const int index, const int order, const float t ) const; 1816 }; 1817 1818 /* 1819 ==================== 1820 idCurve_BSpline::idCurve_NaturalCubicSpline 1821 ==================== 1822 */ 1823 template< class type > 1824 ID_INLINE idCurve_BSpline<type>::idCurve_BSpline() { 1825 order = 4; // default to cubic 1826 } 1827 1828 /* 1829 ==================== 1830 idCurve_BSpline::GetCurrentValue 1831 1832 get the value for the given time 1833 ==================== 1834 */ 1835 template< class type > 1836 ID_INLINE type idCurve_BSpline<type>::GetCurrentValue( const float time ) const { 1837 int i, j, k; 1838 float clampedTime; 1839 type v; 1840 1841 if ( this->times.Num() == 1 ) { 1842 return this->values[0]; 1843 } 1844 1845 clampedTime = this->ClampedTime( time ); 1846 i = this->IndexForTime( clampedTime ); 1847 v = this->values[0] - this->values[0]; //-V501 1848 for ( j = 0; j < order; j++ ) { 1849 k = i + j - ( order >> 1 ); 1850 v += Basis( k-2, order, clampedTime ) * this->ValueForIndex( k ); 1851 } 1852 return v; 1853 } 1854 1855 /* 1856 ==================== 1857 idCurve_BSpline::GetCurrentFirstDerivative 1858 1859 get the first derivative for the given time 1860 ==================== 1861 */ 1862 template< class type > 1863 ID_INLINE type idCurve_BSpline<type>::GetCurrentFirstDerivative( const float time ) const { 1864 int i, j, k; 1865 float clampedTime; 1866 type v; 1867 1868 if ( this->times.Num() == 1 ) { 1869 return this->values[0]; 1870 } 1871 1872 clampedTime = this->ClampedTime( time ); 1873 i = this->IndexForTime( clampedTime ); 1874 v = this->values[0] - this->values[0]; //-V501 1875 for ( j = 0; j < order; j++ ) { 1876 k = i + j - ( order >> 1 ); 1877 v += BasisFirstDerivative( k-2, order, clampedTime ) * this->ValueForIndex( k ); 1878 } 1879 return v; 1880 } 1881 1882 /* 1883 ==================== 1884 idCurve_BSpline::GetCurrentSecondDerivative 1885 1886 get the second derivative for the given time 1887 ==================== 1888 */ 1889 template< class type > 1890 ID_INLINE type idCurve_BSpline<type>::GetCurrentSecondDerivative( const float time ) const { 1891 int i, j, k; 1892 float clampedTime; 1893 type v; 1894 1895 if ( this->times.Num() == 1 ) { 1896 return this->values[0]; 1897 } 1898 1899 clampedTime = this->ClampedTime( time ); 1900 i = this->IndexForTime( clampedTime ); 1901 v = this->values[0] - this->values[0]; //-V501 1902 for ( j = 0; j < order; j++ ) { 1903 k = i + j - ( order >> 1 ); 1904 v += BasisSecondDerivative( k-2, order, clampedTime ) * this->ValueForIndex( k ); 1905 } 1906 return v; 1907 } 1908 1909 /* 1910 ==================== 1911 idCurve_BSpline::Basis 1912 1913 spline basis function 1914 ==================== 1915 */ 1916 template< class type > 1917 ID_INLINE float idCurve_BSpline<type>::Basis( const int index, const int order, const float t ) const { 1918 if ( order <= 1 ) { 1919 if ( this->TimeForIndex( index ) < t && t <= this->TimeForIndex( index + 1 ) ) { 1920 return 1.0f; 1921 } else { 1922 return 0.0f; 1923 } 1924 } else { 1925 float sum = 0.0f; 1926 float d1 = this->TimeForIndex( index+order-1 ) - this->TimeForIndex( index ); 1927 if ( d1 != 0.0f ) { 1928 sum += (float) ( t - this->TimeForIndex( index ) ) * Basis( index, order-1, t ) / d1; 1929 } 1930 1931 float d2 = this->TimeForIndex( index+order ) - this->TimeForIndex( index+1 ); 1932 if ( d2 != 0.0f ) { 1933 sum += (float) ( this->TimeForIndex( index+order ) - t ) * Basis( index+1, order-1, t ) / d2; 1934 } 1935 return sum; 1936 } 1937 } 1938 1939 /* 1940 ==================== 1941 idCurve_BSpline::BasisFirstDerivative 1942 1943 first derivative of spline basis function 1944 ==================== 1945 */ 1946 template< class type > 1947 ID_INLINE float idCurve_BSpline<type>::BasisFirstDerivative( const int index, const int order, const float t ) const { 1948 return ( Basis( index, order-1, t ) - Basis( index+1, order-1, t ) ) * 1949 (float) ( order - 1 ) / ( this->TimeForIndex( index + ( order - 1 ) - 2 ) - this->TimeForIndex( index - 2 ) ); 1950 } 1951 1952 /* 1953 ==================== 1954 idCurve_BSpline::BasisSecondDerivative 1955 1956 second derivative of spline basis function 1957 ==================== 1958 */ 1959 template< class type > 1960 ID_INLINE float idCurve_BSpline<type>::BasisSecondDerivative( const int index, const int order, const float t ) const { 1961 return ( BasisFirstDerivative( index, order-1, t ) - BasisFirstDerivative( index+1, order-1, t ) ) * 1962 (float) ( order - 1 ) / ( this->TimeForIndex( index + ( order - 1 ) - 2 ) - this->TimeForIndex( index - 2 ) ); 1963 } 1964 1965 1966 /* 1967 =============================================================================== 1968 1969 Uniform Non-Rational Cubic B-Spline template. 1970 1971 =============================================================================== 1972 */ 1973 1974 template< class type > 1975 class idCurve_UniformCubicBSpline : public idCurve_BSpline<type> { 1976 1977 public: 1978 idCurve_UniformCubicBSpline(); 1979 1980 virtual type GetCurrentValue( const float time ) const; 1981 virtual type GetCurrentFirstDerivative( const float time ) const; 1982 virtual type GetCurrentSecondDerivative( const float time ) const; 1983 1984 protected: 1985 void Basis( const int index, const float t, float *bvals ) const; 1986 void BasisFirstDerivative( const int index, const float t, float *bvals ) const; 1987 void BasisSecondDerivative( const int index, const float t, float *bvals ) const; 1988 }; 1989 1990 /* 1991 ==================== 1992 idCurve_UniformCubicBSpline::idCurve_UniformCubicBSpline 1993 ==================== 1994 */ 1995 template< class type > 1996 ID_INLINE idCurve_UniformCubicBSpline<type>::idCurve_UniformCubicBSpline() { 1997 this->order = 4; // always cubic 1998 } 1999 2000 /* 2001 ==================== 2002 idCurve_UniformCubicBSpline::GetCurrentValue 2003 2004 get the value for the given time 2005 ==================== 2006 */ 2007 template< class type > 2008 ID_INLINE type idCurve_UniformCubicBSpline<type>::GetCurrentValue( const float time ) const { 2009 int i, j, k; 2010 float bvals[4], clampedTime; 2011 type v; 2012 2013 if ( this->times.Num() == 1 ) { 2014 return this->values[0]; 2015 } 2016 2017 clampedTime = this->ClampedTime( time ); 2018 i = this->IndexForTime( clampedTime ); 2019 Basis( i-1, clampedTime, bvals ); 2020 v = this->values[0] - this->values[0]; //-V501 2021 for ( j = 0; j < 4; j++ ) { 2022 k = i + j - 2; 2023 v += bvals[j] * this->ValueForIndex( k ); 2024 } 2025 return v; 2026 } 2027 2028 /* 2029 ==================== 2030 idCurve_UniformCubicBSpline::GetCurrentFirstDerivative 2031 2032 get the first derivative for the given time 2033 ==================== 2034 */ 2035 template< class type > 2036 ID_INLINE type idCurve_UniformCubicBSpline<type>::GetCurrentFirstDerivative( const float time ) const { 2037 int i, j, k; 2038 float bvals[4], d, clampedTime; 2039 type v; 2040 2041 if ( this->times.Num() == 1 ) { 2042 return ( this->values[0] - this->values[0] ); //-V501 2043 } 2044 2045 clampedTime = this->ClampedTime( time ); 2046 i = this->IndexForTime( clampedTime ); 2047 BasisFirstDerivative( i-1, clampedTime, bvals ); 2048 v = this->values[0] - this->values[0]; //-V501 2049 for ( j = 0; j < 4; j++ ) { 2050 k = i + j - 2; 2051 v += bvals[j] * this->ValueForIndex( k ); 2052 } 2053 d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) ); 2054 return v / d; 2055 } 2056 2057 /* 2058 ==================== 2059 idCurve_UniformCubicBSpline::GetCurrentSecondDerivative 2060 2061 get the second derivative for the given time 2062 ==================== 2063 */ 2064 template< class type > 2065 ID_INLINE type idCurve_UniformCubicBSpline<type>::GetCurrentSecondDerivative( const float time ) const { 2066 int i, j, k; 2067 float bvals[4], d, clampedTime; 2068 type v; 2069 2070 if ( this->times.Num() == 1 ) { 2071 return ( this->values[0] - this->values[0] ); //-V501 2072 } 2073 2074 clampedTime = this->ClampedTime( time ); 2075 i = this->IndexForTime( clampedTime ); 2076 BasisSecondDerivative( i-1, clampedTime, bvals ); 2077 v = this->values[0] - this->values[0]; //-V501 2078 for ( j = 0; j < 4; j++ ) { 2079 k = i + j - 2; 2080 v += bvals[j] * this->ValueForIndex( k ); 2081 } 2082 d = ( this->TimeForIndex( i ) - this->TimeForIndex( i-1 ) ); 2083 return v / ( d * d ); 2084 } 2085 2086 /* 2087 ==================== 2088 idCurve_UniformCubicBSpline::Basis 2089 2090 spline basis functions 2091 ==================== 2092 */ 2093 template< class type > 2094 ID_INLINE void idCurve_UniformCubicBSpline<type>::Basis( const int index, const float t, float *bvals ) const { 2095 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 2096 bvals[0] = ( ( ( -s + 3.0f ) * s - 3.0f ) * s + 1.0f ) * ( 1.0f / 6.0f ); 2097 bvals[1] = ( ( ( 3.0f * s - 6.0f ) * s ) * s + 4.0f ) * ( 1.0f / 6.0f ); 2098 bvals[2] = ( ( ( -3.0f * s + 3.0f ) * s + 3.0f ) * s + 1.0f ) * ( 1.0f / 6.0f ); 2099 bvals[3] = ( s * s * s ) * ( 1.0f / 6.0f ); 2100 } 2101 2102 /* 2103 ==================== 2104 idCurve_UniformCubicBSpline::BasisFirstDerivative 2105 2106 first derivative of spline basis functions 2107 ==================== 2108 */ 2109 template< class type > 2110 ID_INLINE void idCurve_UniformCubicBSpline<type>::BasisFirstDerivative( const int index, const float t, float *bvals ) const { 2111 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 2112 bvals[0] = -0.5f * s * s + s - 0.5f; 2113 bvals[1] = 1.5f * s * s - 2.0f * s; 2114 bvals[2] = -1.5f * s * s + s + 0.5f; 2115 bvals[3] = 0.5f * s * s; 2116 } 2117 2118 /* 2119 ==================== 2120 idCurve_UniformCubicBSpline::BasisSecondDerivative 2121 2122 second derivative of spline basis functions 2123 ==================== 2124 */ 2125 template< class type > 2126 ID_INLINE void idCurve_UniformCubicBSpline<type>::BasisSecondDerivative( const int index, const float t, float *bvals ) const { 2127 float s = (float) ( t - this->TimeForIndex( index ) ) / ( this->TimeForIndex( index+1 ) - this->TimeForIndex( index ) ); 2128 bvals[0] = -s + 1.0f; 2129 bvals[1] = 3.0f * s - 2.0f; 2130 bvals[2] = -3.0f * s + 1.0f; 2131 bvals[3] = s; 2132 } 2133 2134 2135 /* 2136 =============================================================================== 2137 2138 Non-Uniform Non-Rational B-Spline (NUBS) template. 2139 2140 =============================================================================== 2141 */ 2142 2143 template< class type > 2144 class idCurve_NonUniformBSpline : public idCurve_BSpline<type> { 2145 2146 public: 2147 idCurve_NonUniformBSpline(); 2148 2149 virtual type GetCurrentValue( const float time ) const; 2150 virtual type GetCurrentFirstDerivative( const float time ) const; 2151 virtual type GetCurrentSecondDerivative( const float time ) const; 2152 2153 protected: 2154 void Basis( const int index, const int order, const float t, float *bvals ) const; 2155 void BasisFirstDerivative( const int index, const int order, const float t, float *bvals ) const; 2156 void BasisSecondDerivative( const int index, const int order, const float t, float *bvals ) const; 2157 }; 2158 2159 /* 2160 ==================== 2161 idCurve_NonUniformBSpline::idCurve_NonUniformBSpline 2162 ==================== 2163 */ 2164 template< class type > 2165 ID_INLINE idCurve_NonUniformBSpline<type>::idCurve_NonUniformBSpline() { 2166 } 2167 2168 /* 2169 ==================== 2170 idCurve_NonUniformBSpline::GetCurrentValue 2171 2172 get the value for the given time 2173 ==================== 2174 */ 2175 template< class type > 2176 ID_INLINE type idCurve_NonUniformBSpline<type>::GetCurrentValue( const float time ) const { 2177 int i, j, k; 2178 float clampedTime; 2179 type v; 2180 float *bvals = (float *) _alloca16( this->order * sizeof(float) ); 2181 2182 if ( this->times.Num() == 1 ) { 2183 return this->values[0]; 2184 } 2185 2186 clampedTime = this->ClampedTime( time ); 2187 i = this->IndexForTime( clampedTime ); 2188 Basis( i-1, this->order, clampedTime, bvals ); 2189 v = this->values[0] - this->values[0]; //-V501 2190 for ( j = 0; j < this->order; j++ ) { 2191 k = i + j - ( this->order >> 1 ); 2192 v += bvals[j] * this->ValueForIndex( k ); 2193 } 2194 return v; 2195 } 2196 2197 /* 2198 ==================== 2199 idCurve_NonUniformBSpline::GetCurrentFirstDerivative 2200 2201 get the first derivative for the given time 2202 ==================== 2203 */ 2204 template< class type > 2205 ID_INLINE type idCurve_NonUniformBSpline<type>::GetCurrentFirstDerivative( const float time ) const { 2206 int i, j, k; 2207 float clampedTime; 2208 type v; 2209 float *bvals = (float *) _alloca16( this->order * sizeof(float) ); 2210 2211 if ( this->times.Num() == 1 ) { 2212 return ( this->values[0] - this->values[0] ); //-V501 2213 } 2214 2215 clampedTime = this->ClampedTime( time ); 2216 i = this->IndexForTime( clampedTime ); 2217 BasisFirstDerivative( i-1, this->order, clampedTime, bvals ); 2218 v = this->values[0] - this->values[0]; //-V501 2219 for ( j = 0; j < this->order; j++ ) { 2220 k = i + j - ( this->order >> 1 ); 2221 v += bvals[j] * this->ValueForIndex( k ); 2222 } 2223 return v; 2224 } 2225 2226 /* 2227 ==================== 2228 idCurve_NonUniformBSpline::GetCurrentSecondDerivative 2229 2230 get the second derivative for the given time 2231 ==================== 2232 */ 2233 template< class type > 2234 ID_INLINE type idCurve_NonUniformBSpline<type>::GetCurrentSecondDerivative( const float time ) const { 2235 int i, j, k; 2236 float clampedTime; 2237 type v; 2238 float *bvals = (float *) _alloca16( this->order * sizeof(float) ); 2239 2240 if ( this->times.Num() == 1 ) { 2241 return ( this->values[0] - this->values[0] ); //-V501 2242 } 2243 2244 clampedTime = this->ClampedTime( time ); 2245 i = this->IndexForTime( clampedTime ); 2246 BasisSecondDerivative( i-1, this->order, clampedTime, bvals ); 2247 v = this->values[0] - this->values[0]; //-V501 2248 for ( j = 0; j < this->order; j++ ) { 2249 k = i + j - ( this->order >> 1 ); 2250 v += bvals[j] * this->ValueForIndex( k ); 2251 } 2252 return v; 2253 } 2254 2255 /* 2256 ==================== 2257 idCurve_NonUniformBSpline::Basis 2258 2259 spline basis functions 2260 ==================== 2261 */ 2262 template< class type > 2263 ID_INLINE void idCurve_NonUniformBSpline<type>::Basis( const int index, const int order, const float t, float *bvals ) const { 2264 int r, s, i; 2265 float omega; 2266 2267 bvals[order-1] = 1.0f; 2268 for ( r = 2; r <= order; r++ ) { 2269 i = index - r + 1; 2270 bvals[order - r] = 0.0f; 2271 for ( s = order - r + 1; s < order; s++ ) { 2272 i++; 2273 omega = (float) ( t - this->TimeForIndex( i ) ) / ( this->TimeForIndex( i + r - 1 ) - this->TimeForIndex( i ) ); 2274 bvals[s - 1] += ( 1.0f - omega ) * bvals[s]; 2275 bvals[s] *= omega; 2276 } 2277 } 2278 } 2279 2280 /* 2281 ==================== 2282 idCurve_NonUniformBSpline::BasisFirstDerivative 2283 2284 first derivative of spline basis functions 2285 ==================== 2286 */ 2287 template< class type > 2288 ID_INLINE void idCurve_NonUniformBSpline<type>::BasisFirstDerivative( const int index, const int order, const float t, float *bvals ) const { 2289 int i; 2290 2291 Basis( index, order-1, t, bvals+1 ); 2292 bvals[0] = 0.0f; 2293 for ( i = 0; i < order-1; i++ ) { 2294 bvals[i] -= bvals[i+1]; 2295 bvals[i] *= (float) ( order - 1) / ( this->TimeForIndex( index + i + (order-1) - 2 ) - this->TimeForIndex( index + i - 2 ) ); 2296 } 2297 bvals[i] *= (float) ( order - 1) / ( this->TimeForIndex( index + i + (order-1) - 2 ) - this->TimeForIndex( index + i - 2 ) ); 2298 } 2299 2300 /* 2301 ==================== 2302 idCurve_NonUniformBSpline::BasisSecondDerivative 2303 2304 second derivative of spline basis functions 2305 ==================== 2306 */ 2307 template< class type > 2308 ID_INLINE void idCurve_NonUniformBSpline<type>::BasisSecondDerivative( const int index, const int order, const float t, float *bvals ) const { 2309 int i; 2310 2311 BasisFirstDerivative( index, order-1, t, bvals+1 ); 2312 bvals[0] = 0.0f; 2313 for ( i = 0; i < order-1; i++ ) { 2314 bvals[i] -= bvals[i+1]; 2315 bvals[i] *= (float) ( order - 1) / ( this->TimeForIndex( index + i + (order-1) - 2 ) - this->TimeForIndex( index + i - 2 ) ); 2316 } 2317 bvals[i] *= (float) ( order - 1) / ( this->TimeForIndex( index + i + (order-1) - 2 ) - this->TimeForIndex( index + i - 2 ) ); 2318 } 2319 2320 2321 /* 2322 =============================================================================== 2323 2324 Non-Uniform Rational B-Spline (NURBS) template. 2325 2326 =============================================================================== 2327 */ 2328 2329 template< class type > 2330 class idCurve_NURBS : public idCurve_NonUniformBSpline<type> { 2331 2332 public: 2333 idCurve_NURBS(); 2334 2335 virtual int AddValue( const float time, const type &value ); 2336 virtual int AddValue( const float time, const type &value, const float weight ); 2337 virtual void RemoveIndex( const int index ) { this->values.RemoveIndex(index); this->times.RemoveIndex(index); weights.RemoveIndex(index); } 2338 virtual void Clear() { this->values.Clear(); this->times.Clear(); weights.Clear(); this->currentIndex = -1; } 2339 2340 virtual type GetCurrentValue( const float time ) const; 2341 virtual type GetCurrentFirstDerivative( const float time ) const; 2342 virtual type GetCurrentSecondDerivative( const float time ) const; 2343 2344 protected: 2345 idList<float> weights; 2346 2347 float WeightForIndex( const int index ) const; 2348 }; 2349 2350 /* 2351 ==================== 2352 idCurve_NURBS::idCurve_NURBS 2353 ==================== 2354 */ 2355 template< class type > 2356 ID_INLINE idCurve_NURBS<type>::idCurve_NURBS() { 2357 } 2358 2359 /* 2360 ==================== 2361 idCurve_NURBS::AddValue 2362 2363 add a timed/value pair to the spline 2364 returns the index to the inserted pair 2365 ==================== 2366 */ 2367 template< class type > 2368 ID_INLINE int idCurve_NURBS<type>::AddValue( const float time, const type &value ) { 2369 int i; 2370 2371 i = this->IndexForTime( time ); 2372 this->times.Insert( time, i ); 2373 this->values.Insert( value, i ); 2374 weights.Insert( 1.0f, i ); 2375 return i; 2376 } 2377 2378 /* 2379 ==================== 2380 idCurve_NURBS::AddValue 2381 2382 add a timed/value pair to the spline 2383 returns the index to the inserted pair 2384 ==================== 2385 */ 2386 template< class type > 2387 ID_INLINE int idCurve_NURBS<type>::AddValue( const float time, const type &value, const float weight ) { 2388 int i; 2389 2390 i = this->IndexForTime( time ); 2391 this->times.Insert( time, i ); 2392 this->values.Insert( value, i ); 2393 weights.Insert( weight, i ); 2394 return i; 2395 } 2396 2397 /* 2398 ==================== 2399 idCurve_NURBS::GetCurrentValue 2400 2401 get the value for the given time 2402 ==================== 2403 */ 2404 template< class type > 2405 ID_INLINE type idCurve_NURBS<type>::GetCurrentValue( const float time ) const { 2406 int i, j, k; 2407 float w, b, *bvals, clampedTime; 2408 type v; 2409 2410 if ( this->times.Num() == 1 ) { 2411 return this->values[0]; 2412 } 2413 2414 bvals = (float *) _alloca16( this->order * sizeof(float) ); 2415 2416 clampedTime = this->ClampedTime( time ); 2417 i = this->IndexForTime( clampedTime ); 2418 this->Basis( i-1, this->order, clampedTime, bvals ); 2419 v = this->values[0] - this->values[0]; //-V501 2420 w = 0.0f; 2421 for ( j = 0; j < this->order; j++ ) { 2422 k = i + j - ( this->order >> 1 ); 2423 b = bvals[j] * WeightForIndex( k ); 2424 w += b; 2425 v += b * this->ValueForIndex( k ); 2426 } 2427 return v / w; 2428 } 2429 2430 /* 2431 ==================== 2432 idCurve_NURBS::GetCurrentFirstDerivative 2433 2434 get the first derivative for the given time 2435 ==================== 2436 */ 2437 template< class type > 2438 ID_INLINE type idCurve_NURBS<type>::GetCurrentFirstDerivative( const float time ) const { 2439 int i, j, k; 2440 float w, wb, wd1, b, d1, *bvals, *d1vals, clampedTime; 2441 type v, vb, vd1; 2442 2443 if ( this->times.Num() == 1 ) { 2444 return this->values[0]; 2445 } 2446 2447 bvals = (float *) _alloca16( this->order * sizeof(float) ); 2448 d1vals = (float *) _alloca16( this->order * sizeof(float) ); 2449 2450 clampedTime = this->ClampedTime( time ); 2451 i = this->IndexForTime( clampedTime ); 2452 this->Basis( i-1, this->order, clampedTime, bvals ); 2453 this->BasisFirstDerivative( i-1, this->order, clampedTime, d1vals ); 2454 vb = vd1 = this->values[0] - this->values[0]; //-V501 2455 wb = wd1 = 0.0f; 2456 for ( j = 0; j < this->order; j++ ) { 2457 k = i + j - ( this->order >> 1 ); 2458 w = WeightForIndex( k ); 2459 b = bvals[j] * w; 2460 d1 = d1vals[j] * w; 2461 wb += b; 2462 wd1 += d1; 2463 v = this->ValueForIndex( k ); 2464 vb += b * v; 2465 vd1 += d1 * v; 2466 } 2467 return ( wb * vd1 - vb * wd1 ) / ( wb * wb ); 2468 } 2469 2470 /* 2471 ==================== 2472 idCurve_NURBS::GetCurrentSecondDerivative 2473 2474 get the second derivative for the given time 2475 ==================== 2476 */ 2477 template< class type > 2478 ID_INLINE type idCurve_NURBS<type>::GetCurrentSecondDerivative( const float time ) const { 2479 int i, j, k; 2480 float w, wb, wd1, wd2, b, d1, d2, *bvals, *d1vals, *d2vals, clampedTime; 2481 type v, vb, vd1, vd2; 2482 2483 if ( this->times.Num() == 1 ) { 2484 return this->values[0]; 2485 } 2486 2487 bvals = (float *) _alloca16( this->order * sizeof(float) ); 2488 d1vals = (float *) _alloca16( this->order * sizeof(float) ); 2489 d2vals = (float *) _alloca16( this->order * sizeof(float) ); 2490 2491 clampedTime = this->ClampedTime( time ); 2492 i = this->IndexForTime( clampedTime ); 2493 this->Basis( i-1, this->order, clampedTime, bvals ); 2494 this->BasisFirstDerivative( i-1, this->order, clampedTime, d1vals ); 2495 this->BasisSecondDerivative( i-1, this->order, clampedTime, d2vals ); 2496 vb = vd1 = vd2 = this->values[0] - this->values[0]; //-V501 2497 wb = wd1 = wd2 = 0.0f; 2498 for ( j = 0; j < this->order; j++ ) { 2499 k = i + j - ( this->order >> 1 ); 2500 w = WeightForIndex( k ); 2501 b = bvals[j] * w; 2502 d1 = d1vals[j] * w; 2503 d2 = d2vals[j] * w; 2504 wb += b; 2505 wd1 += d1; 2506 wd2 += d2; 2507 v = this->ValueForIndex( k ); 2508 vb += b * v; 2509 vd1 += d1 * v; 2510 vd2 += d2 * v; 2511 } 2512 return ( ( wb * wb ) * ( wb * vd2 - vb * wd2 ) - ( wb * vd1 - vb * wd1 ) * 2.0f * wb * wd1 ) / ( wb * wb * wb * wb ); 2513 } 2514 2515 /* 2516 ==================== 2517 idCurve_NURBS::WeightForIndex 2518 2519 get the weight for the given index 2520 ==================== 2521 */ 2522 template< class type > 2523 ID_INLINE float idCurve_NURBS<type>::WeightForIndex( const int index ) const { 2524 int n = weights.Num()-1; 2525 2526 if ( index < 0 ) { 2527 if ( this->boundaryType == idCurve_Spline<type>::BT_CLOSED ) { 2528 return weights[ weights.Num() + index % weights.Num() ]; 2529 } else { 2530 return weights[0] + index * ( weights[1] - weights[0] ); 2531 } 2532 } else if ( index > n ) { 2533 if ( this->boundaryType == idCurve_Spline<type>::BT_CLOSED ) { 2534 return weights[ index % weights.Num() ]; 2535 } else { 2536 return weights[n] + ( index - n ) * ( weights[n] - weights[n-1] ); 2537 } 2538 } 2539 return weights[index]; 2540 } 2541 2542 #endif /* !__MATH_CURVE_H__ */