1 //******************************************************************************
2 ///
3 /// @file core/material/warp.cpp
4 ///
5 /// Implementation of warps.
6 ///
7 /// The code in this file implements functions that warp or modify the point at
8 /// which a texture pattern is evaluated.
9 ///
10 /// @copyright
11 /// @parblock
12 ///
13 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
14 /// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd.
15 ///
16 /// POV-Ray is free software: you can redistribute it and/or modify
17 /// it under the terms of the GNU Affero General Public License as
18 /// published by the Free Software Foundation, either version 3 of the
19 /// License, or (at your option) any later version.
20 ///
21 /// POV-Ray is distributed in the hope that it will be useful,
22 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
23 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 /// GNU Affero General Public License for more details.
25 ///
26 /// You should have received a copy of the GNU Affero General Public License
27 /// along with this program.  If not, see <http://www.gnu.org/licenses/>.
28 ///
29 /// ----------------------------------------------------------------------------
30 ///
31 /// POV-Ray is based on the popular DKB raytracer version 2.12.
32 /// DKBTrace was originally written by David K. Buck.
33 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
34 ///
35 /// @endparblock
36 ///
37 //******************************************************************************
38 
39 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
40 #include "core/material/warp.h"
41 
42 #include "base/pov_err.h"
43 
44 #include "core/material/noise.h"
45 #include "core/material/pattern.h"
46 #include "core/material/texture.h"
47 #include "core/math/matrix.h"
48 #include "core/math/randomsequence.h"
49 
50 // this must be the last file included
51 #include "base/povdebug.h"
52 
53 namespace pov
54 {
55 
56 /*****************************************************************************
57 * Local preprocessor defines
58 ******************************************************************************/
59 
60 const DBL COORDINATE_LIMIT = 1.0e17;
61 
62 /*****************************************************************************
63 * Static functions
64 ******************************************************************************/
65 
66 static RandomDoubleSequence WarpRands(0.0, 1.0, 32768);
67 
68 /*****************************************************************************
69 *
70 * FUNCTION
71 *
72 *   Warp_EPoint
73 *
74 * INPUT
75 *
76 *   EPoint -- The original point in 3d space at which a pattern
77 *   is evaluated.
78 *   TPat   -- Texture pattern struct
79 *
80 * OUTPUT
81 *
82 *   TPoint -- Point after turbulence and transform
83 *   have been applied
84 *
85 * RETURNS
86 *
87 * AUTHOR
88 *
89 *   POV-Ray Team
90 *
91 * DESCRIPTION
92 *
93 * CHANGES
94 *
95 ******************************************************************************/
96 
Warp_EPoint(Vector3d & TPoint,const Vector3d & EPoint,const TPATTERN * TPat)97 void Warp_EPoint (Vector3d& TPoint, const Vector3d& EPoint, const TPATTERN *TPat)
98 {
99     WarpList& warps=TPat->pattern->warps;
100 
101     TPoint = EPoint;
102 
103     for (WarpList::reverse_iterator iWarp = warps.rbegin(); iWarp != warps.rend(); iWarp ++)
104     {
105         WarpPtr& warp = *iWarp;
106         warp->WarpPoint(TPoint);
107     }
108 
109     for (int i=X; i<=Z; i++)
110     {
111         if (TPoint[i] > COORDINATE_LIMIT)
112             TPoint[i]= COORDINATE_LIMIT;
113         else if (TPoint[i] < -COORDINATE_LIMIT)
114             TPoint[i] = -COORDINATE_LIMIT;
115     }
116 }
117 
WarpPoint(Vector3d & TPoint) const118 bool BlackHoleWarp::WarpPoint(Vector3d& TPoint) const
119 {
120     Vector3d C = Center;
121 
122     if (Repeat)
123     {
124         int blockX = 0, blockY = 0, blockZ = 0;
125 
126         /* first, get the block number we're in for each dimension  */
127         /* block numbers are (currently) calculated relative to 0   */
128         /* we use floor () since it correctly returns -1 for the
129             first block below 0 in each axis                         */
130         /* one final point - we could run into overflow problems if
131             the repeat vector was small and the scene very large.    */
132         if (Repeat_Vector[X] >= EPSILON)
133             blockX = (int) floor (TPoint[X] / Repeat_Vector[X]);
134 
135         if (Repeat_Vector[Y] >= EPSILON)
136             blockY = (int) floor (TPoint[Y] / Repeat_Vector[Y]);
137 
138         if (Repeat_Vector[Z] >= EPSILON)
139             blockZ = (int) floor (TPoint[Z] / Repeat_Vector[Z]);
140 
141         if (Uncertain)
142         {
143             /* if the position is uncertain calculate the new one first */
144             /* this will allow the same numbers to be returned by frand */
145 
146             int seed = Hash3d (blockX, blockY, blockZ);
147             C[X] += WarpRands(seed)     * Uncertainty_Vector[X];
148             C[Y] += WarpRands(seed + 1) * Uncertainty_Vector[Y];
149             C[Z] += WarpRands(seed + 2) * Uncertainty_Vector[Z];
150         }
151 
152         C[X] += Repeat_Vector[X] * blockX;
153         C[Y] += Repeat_Vector[Y] * blockY;
154         C[Z] += Repeat_Vector[Z] * blockZ;
155     }
156 
157     Vector3d Delta = TPoint - C;
158     DBL Length = Delta.length();
159 
160     /* Length is the distance from the centre of the black hole */
161     if (Length >= Radius)
162         return true;
163 
164     if (Type == 0)
165     {
166         /* now convert the length to a proportion (0 to 1) that the point
167             is from the edge of the black hole. a point on the perimeter
168             of the black hole will be 0.0; a point at the centre will be
169             1.0; a point exactly halfway will be 0.5, and so forth. */
170         Length = (Radius - Length) / Radius;
171 
172         /* Strength is the magnitude of the transformation effect. firstly,
173             apply the Power variable to Length. this is meant to provide a
174             means of controlling how fast the power of the Black Hole falls
175             off from its centre. if Power is 2.0, then the effect is inverse
176             square. increasing power will cause the Black Hole to be a lot
177             weaker in its effect towards its perimeter.
178 
179             finally we multiply Strength with the Black Hole's Strength
180             variable. if the resultant value exceeds 1.0 we clip it to 1.0.
181             this means a point will never be transformed by more than its
182             original distance from the centre. the result of this clipping
183             is that you will have an 'exclusion' area near the centre of
184             the black hole where all points whose final value exceeded or
185             equalled 1.0 were moved by a fixed amount. this only happens
186             if the Strength value of the Black Hole was greater than one. */
187 
188         DBL S = pow (Length, Power) * Strength;
189         if (S > 1.0) S = 1.0;
190 
191         /* if the Black Hole is inverted, it gives the impression of 'push-
192             ing' the pattern away from its centre. otherwise it sucks. */
193         Delta *= (Inverted ? -S : S);
194 
195         /* add the scaled Delta to the input point to end up with TPoint. */
196         TPoint += Delta;
197     }
198 
199     return true;
200 }
201 
WarpPoint(Vector3d & EPoint) const202 bool CubicWarp::WarpPoint(Vector3d& EPoint) const
203 {
204     DBL x = EPoint[X], y = EPoint[Y], z = EPoint[Z];
205     const DBL ax = fabs(x), ay = fabs(y), az = fabs(z);
206 
207     if(x >= 0 && x >= ay && x >= az)
208     {
209         EPoint[X] = 0.75 - 0.25*(z/x+1.0)/2.0;
210         EPoint[Y] = 1.0/3.0 + (1.0/3.0)*(y/x+1.0)/2.0;
211         EPoint[Z] = x;
212     }
213     else if(y >= 0 && y >= ax && y >= az)
214     {
215         EPoint[X] = 0.25 + 0.25*(x/y+1.0)/2.0;
216         EPoint[Y] = 1.0 - (1.0/3.0)*(z/y+1.0)/2.0;
217         EPoint[Z] = y;
218     }
219     else if(z >= 0 && z >= ax && z >= ay)
220     {
221         EPoint[X] = 0.25 + 0.25*(x/z+1.0)/2.0;
222         EPoint[Y] = 1.0/3.0 + (1.0/3.0)*(y/z+1.0)/2.0;
223         EPoint[Z] = z;
224     }
225     else if(x < 0 && x <= -ay && x <= -az)
226     {
227         x = -x;
228         EPoint[X] = 0.25*(z/x+1.0)/2.0;
229         EPoint[Y] = 1.0/3.0 + (1.0/3.0)*(y/x+1.0)/2.0;
230         EPoint[Z] = x;
231     }
232     else if(y < 0 && y <= -ax && y <= -az)
233     {
234         y = -y;
235         EPoint[X] = 0.25 + 0.25*(x/y+1.0)/2.0;
236         EPoint[Y] = (1.0/3.0)*(z/y+1.0)/2.0;
237         EPoint[Z] = y;
238     }
239     else
240     {
241         z = -z;
242         EPoint[X] = 1.0 - 0.25*(x/z+1.0)/2.0;
243         EPoint[Y] = 1.0/3.0 + (1.0/3.0)*(y/z+1.0)/2.0;
244         EPoint[Z] = z;
245     }
246 
247     return 1;
248 }
249 
WarpPoint(Vector3d & EPoint) const250 bool CylindricalWarp::WarpPoint(Vector3d& EPoint) const
251 {
252     DBL len, theta;
253     DBL x = EPoint[X];
254     DBL y = EPoint[Y];
255     DBL z = EPoint[Z];
256 
257     // Determine its angle from the point (1, 0, 0) in the x-z plane.
258     len = sqrt(x * x + z * z);
259 
260     if(len == 0.0)
261         return false;
262     else
263     {
264         if(z == 0.0)
265         {
266             if(x > 0)
267                 theta = 0.0;
268             else
269                 theta = M_PI;
270         }
271         else
272         {
273             theta = acos(x / len);
274             if(z < 0.0)
275                 theta = TWO_M_PI - theta;
276         }
277 
278         theta /= TWO_M_PI;  // This will be from 0 to 1
279     }
280 
281     if(DistExp == 1.0)
282         theta *= len;
283     else if (DistExp != 0.0)
284         theta *= pow(len, DistExp);
285 
286     x = theta;
287     z = len;
288 
289     if((Orientation_Vector[X] == 0.0) &&
290        (Orientation_Vector[Y] == 0.0) &&
291        (Orientation_Vector[Z] == 1.0))
292     {
293         EPoint[X] = x;
294         EPoint[Y] = y;
295         EPoint[Z] = z;
296     }
297     else
298     {
299         EPoint[X] = (Orientation_Vector[X] * z) +
300                     (Orientation_Vector[Y] * x) +
301                     (Orientation_Vector[Z] * x);
302         EPoint[Y] = (Orientation_Vector[X] * y) +
303                     (Orientation_Vector[Y] * -z) +
304                     (Orientation_Vector[Z] * y);
305         EPoint[Z] = (Orientation_Vector[X] * -x) +
306                     (Orientation_Vector[Y] * y) +
307                     (Orientation_Vector[Z] * z);
308     }
309 
310     return true;
311 }
312 
WarpPoint(Vector3d & TPoint) const313 bool IdentityWarp::WarpPoint(Vector3d& TPoint) const
314 {
315     return true;
316 }
317 
WarpPoint(Vector3d & EPoint) const318 bool PlanarWarp::WarpPoint(Vector3d& EPoint) const
319 {
320     DBL x = EPoint[X];
321     DBL z = OffSet;
322     DBL y = EPoint[Y];
323 
324     if((Orientation_Vector[X] == 0.0) &&
325        (Orientation_Vector[Y] == 0.0) &&
326        (Orientation_Vector[Z] == 1.0))
327     {
328         EPoint[X] = x;
329         EPoint[Y] = y;
330         EPoint[Z] = z;
331     }
332     else
333     {
334         EPoint[X] = (Orientation_Vector[X] * z) +
335                     (Orientation_Vector[Y] * x) +
336                     (Orientation_Vector[Z] * x);
337         EPoint[Y] = (Orientation_Vector[X] * y) +
338                     (Orientation_Vector[Y] * -z) +
339                     (Orientation_Vector[Z] * y);
340         EPoint[Z] = (Orientation_Vector[X] * -x) +
341                     (Orientation_Vector[Y] * y) +
342                     (Orientation_Vector[Z] * z);
343     }
344 
345     return true;
346 }
347 
WarpPoint(Vector3d & TPoint) const348 bool RepeatWarp::WarpPoint(Vector3d& TPoint) const
349 {
350     SNGL BlkNum = (SNGL)floor(TPoint[Axis]/Width);
351 
352     TPoint[Axis] -= BlkNum*Width;
353 
354     if (((int)BlkNum) & 1)
355     {
356         TPoint *= Flip;
357         if ( Flip[Axis] < 0 )
358             TPoint[Axis] += Width;
359     }
360 
361     TPoint += (DBL)BlkNum * Offset;
362 
363     return true;
364 }
365 
WarpPoint(Vector3d & EPoint) const366 bool SphericalWarp::WarpPoint(Vector3d& EPoint) const
367 {
368     DBL len, phi, theta,dist;
369     DBL x = EPoint[X];
370     DBL y = EPoint[Y];
371     DBL z = EPoint[Z];
372 
373     // Make sure this vector is on the unit sphere.
374 
375     dist = sqrt(x * x + y * y + z * z);
376 
377     if(dist == 0.0)
378         return 0;
379     else
380     {
381         x /= dist;
382         y /= dist;
383         z /= dist;
384     }
385 
386     // Determine its angle from the x-z plane.
387     phi = 0.5 + asin(y) / M_PI; // This will be from 0 to 1
388 
389     // Determine its angle from the point (1, 0, 0) in the x-z plane.
390     len = sqrt(x * x + z * z);
391     if(len == 0.0)
392     {
393         // This point is at one of the poles. Any value of xcoord will be ok...
394         theta = 0;
395     }
396     else
397     {
398         if(z == 0.0)
399         {
400             if(x > 0)
401                 theta = 0.0;
402             else
403                 theta = M_PI;
404         }
405         else
406         {
407             theta = acos(x / len);
408             if (z < 0.0)
409                 theta = TWO_M_PI - theta;
410         }
411         theta /= TWO_M_PI;  /* This will be from 0 to 1 */
412     }
413 
414     if(DistExp == 1.0)
415     {
416         theta *= dist;
417         phi *= dist;
418     }
419     else if(DistExp != 0.0)
420     {
421         theta *= pow(dist, DistExp);
422         phi *= pow(dist, DistExp);
423     }
424 
425     x = theta;
426     z = dist;
427     y = phi;
428 
429     if((Orientation_Vector[X] == 0.0) &&
430        (Orientation_Vector[Y] == 0.0) &&
431        (Orientation_Vector[Z] == 1.0))
432     {
433         EPoint[X] = x;
434         EPoint[Y] = y;
435         EPoint[Z] = z;
436     }
437     else
438     {
439         EPoint[X] = (Orientation_Vector[X] * z) +
440                     (Orientation_Vector[Y] * x) +
441                     (Orientation_Vector[Z] * x);
442         EPoint[Y] = (Orientation_Vector[X] * y) +
443                     (Orientation_Vector[Y] * -z) +
444                     (Orientation_Vector[Z] * y);
445         EPoint[Z] = (Orientation_Vector[X] * -x) +
446                     (Orientation_Vector[Y] * y) +
447                     (Orientation_Vector[Z] * z);
448     }
449 
450     return 1;
451 }
452 
WarpPoint(Vector3d & EPoint) const453 bool ToroidalWarp::WarpPoint(Vector3d& EPoint) const
454 {
455     DBL len, phi, theta;
456     DBL r0;
457     DBL x = EPoint[X];
458     DBL y = EPoint[Y];
459     DBL z = EPoint[Z];
460 
461     r0 = MajorRadius;
462 
463     // Determine its angle from the x-axis.
464 
465     len = sqrt(x * x + z * z);
466 
467     if(len == 0.0)
468         return false;
469     else
470     {
471         if(z == 0.0)
472         {
473             if(x > 0)
474                 theta = 0.0;
475             else
476                 theta = M_PI;
477         }
478         else
479         {
480             theta = acos(x / len);
481             if(z < 0.0)
482                 theta = TWO_M_PI - theta;
483         }
484     }
485 
486     theta = 0.0 - theta;
487 
488     // Now rotate about the y-axis to get the point (x, y, z) into the x-y plane.
489 
490     x = len - r0;
491     len = sqrt(x * x + y * y);
492     phi = acos(-x / len);
493     if (y > 0.0)
494         phi = TWO_M_PI - phi;
495 
496     // Determine the parametric coordinates.
497 
498     theta /= (-TWO_M_PI);
499 
500     phi /= TWO_M_PI;
501 
502     if (DistExp == 1.0)
503     {
504         theta *= len;
505         phi *= len;
506     }
507     else if (DistExp != 0.0)
508     {
509         theta *= pow(len, DistExp);
510         phi *= pow(len, DistExp);
511     }
512 
513     x = theta;
514     z = len;
515     y = phi;
516 
517     if((Orientation_Vector[X] == 0.0) &&
518        (Orientation_Vector[Y] == 0.0) &&
519        (Orientation_Vector[Z] == 1.0))
520     {
521         EPoint[X] = x;
522         EPoint[Y] = y;
523         EPoint[Z] = z;
524     }
525     else
526     {
527         EPoint[X] = (Orientation_Vector[X] * z) +
528                     (Orientation_Vector[Y] * x) +
529                     (Orientation_Vector[Z] * x);
530         EPoint[Y] = (Orientation_Vector[X] * y) +
531                     (Orientation_Vector[Y] * -z) +
532                     (Orientation_Vector[Z] * y);
533         EPoint[Z] = (Orientation_Vector[X] * -x) +
534                     (Orientation_Vector[Y] * y) +
535                     (Orientation_Vector[Z] * z);
536     }
537 
538     return true;
539 }
540 
WarpPoint(Vector3d & TPoint) const541 bool TransformWarp::WarpPoint(Vector3d& TPoint) const
542 {
543     MInvTransPoint(TPoint, TPoint, &Trans);
544     return true;
545 }
546 
WarpPoint(Vector3d & TPoint) const547 bool GenericTurbulenceWarp::WarpPoint(Vector3d& TPoint) const
548 {
549     Vector3d PTurbulence;
550     DTurbulence (PTurbulence, TPoint, this);
551     TPoint += PTurbulence * Turbulence;
552     return true;
553 }
554 
555 
556 
Warp_Normal(Vector3d & TNorm,const Vector3d & ENorm,const TPATTERN * TPat,bool DontScaleBumps)557 void Warp_Normal (Vector3d& TNorm, const Vector3d& ENorm, const TPATTERN *TPat, bool DontScaleBumps)
558 {
559     const WarpList& warps = TPat->pattern->warps;
560 
561     if(!DontScaleBumps)
562         TNorm = ENorm.normalized();
563     else
564         TNorm = ENorm;
565 
566     for (WarpList::const_reverse_iterator iWarp = warps.rbegin(); iWarp != warps.rend(); iWarp ++)
567     {
568         const WarpPtr& warp = *iWarp;
569         warp->WarpNormal(TNorm);
570     }
571 
572     if(!DontScaleBumps)
573         TNorm.normalize();
574 }
575 
WarpNormal(Vector3d & TNorm) const576 bool IdentityWarp::WarpNormal(Vector3d& TNorm) const
577 {
578     return true;
579 }
580 
WarpNormal(Vector3d & TNorm) const581 bool TransformWarp::WarpNormal(Vector3d& TNorm) const
582 {
583     MInvTransNormal(TNorm, TNorm, &Trans);
584     return true;
585 }
586 
WarpNormal(Vector3d & TNorm) const587 bool BlackHoleWarp::WarpNormal(Vector3d& TNorm) const           { /* Error("Black Hole Warp not yet implemented for normals"); */   return false; }
WarpNormal(Vector3d & TNorm) const588 bool CubicWarp::WarpNormal(Vector3d& TNorm) const               { /* Error("Cubic Warp not yet implemented for normals"); */        return false; }
WarpNormal(Vector3d & TNorm) const589 bool CylindricalWarp::WarpNormal(Vector3d& TNorm) const         { /* Error("Cylindrical Warp not yet implemented for normals"); */  return false; }
WarpNormal(Vector3d & TNorm) const590 bool PlanarWarp::WarpNormal(Vector3d& TNorm) const              { /* Error("Planar Warp not yet implemented for normals"); */       return false; }
WarpNormal(Vector3d & TNorm) const591 bool RepeatWarp::WarpNormal(Vector3d& TNorm) const              { /* Error("Repeat Warp not yet implemented for normals"); */       return false; }
WarpNormal(Vector3d & TNorm) const592 bool SphericalWarp::WarpNormal(Vector3d& TNorm) const           { /* Error("Spherical Warp not yet implemented for normals"); */    return false; }
WarpNormal(Vector3d & TNorm) const593 bool ToroidalWarp::WarpNormal(Vector3d& TNorm) const            { /* Error("Toroidal Warp not yet implemented for normals"); */     return false; }
WarpNormal(Vector3d & TNorm) const594 bool GenericTurbulenceWarp::WarpNormal(Vector3d& TNorm) const   { /* Error("Turbulence Warp not yet implemented for normals"); */   return false; }
595 
596 
UnWarp_Normal(Vector3d & TNorm,const Vector3d & ENorm,const TPATTERN * TPat,bool DontScaleBumps)597 void UnWarp_Normal (Vector3d& TNorm, const Vector3d& ENorm, const TPATTERN *TPat, bool DontScaleBumps)
598 {
599     const WarpList& warps = TPat->pattern->warps;
600 
601     if(!DontScaleBumps)
602         TNorm = ENorm.normalized();
603     else
604         TNorm = ENorm;
605 
606     for (WarpList::const_iterator iWarp = warps.begin(); iWarp != warps.end(); iWarp ++)
607     {
608         const WarpPtr& warp = *iWarp;
609         warp->UnwarpNormal(TNorm);
610     }
611 
612     if(!DontScaleBumps)
613         TNorm.normalize();
614 }
615 
UnwarpNormal(Vector3d & TNorm) const616 bool IdentityWarp::UnwarpNormal(Vector3d& TNorm) const
617 {
618     return true;
619 }
620 
UnwarpNormal(Vector3d & TNorm) const621 bool TransformWarp::UnwarpNormal(Vector3d& TNorm) const
622 {
623     MTransNormal(TNorm, TNorm, &Trans);
624     return true;
625 }
626 
UnwarpNormal(Vector3d & TNorm) const627 bool BlackHoleWarp::UnwarpNormal(Vector3d& TNorm) const         { /* Error("Black Hole Warp not yet implemented for normals"); */   return false; }
UnwarpNormal(Vector3d & TNorm) const628 bool CubicWarp::UnwarpNormal(Vector3d& TNorm) const             { /* Error("Cubic Warp not yet implemented for normals"); */        return false; }
UnwarpNormal(Vector3d & TNorm) const629 bool CylindricalWarp::UnwarpNormal(Vector3d& TNorm) const       { /* Error("Cylindrical Warp not yet implemented for normals"); */  return false; }
UnwarpNormal(Vector3d & TNorm) const630 bool PlanarWarp::UnwarpNormal(Vector3d& TNorm) const            { /* Error("Planar Warp not yet implemented for normals"); */       return false; }
UnwarpNormal(Vector3d & TNorm) const631 bool RepeatWarp::UnwarpNormal(Vector3d& TNorm) const            { /* Error("Repeat Warp not yet implemented for normals"); */       return false; }
UnwarpNormal(Vector3d & TNorm) const632 bool SphericalWarp::UnwarpNormal(Vector3d& TNorm) const         { /* Error("Spherical Warp not yet implemented for normals"); */    return false; }
UnwarpNormal(Vector3d & TNorm) const633 bool ToroidalWarp::UnwarpNormal(Vector3d& TNorm) const          { /* Error("Toroidal Warp not yet implemented for normals"); */     return false; }
UnwarpNormal(Vector3d & TNorm) const634 bool GenericTurbulenceWarp::UnwarpNormal(Vector3d& TNorm) const { /* Error("Turbulence Warp not yet implemented for normals"); */   return false; }
635 
636 
637 /*****************************************************************************
638 *
639 * FUNCTION
640 *
641 * INPUT
642 *
643 * OUTPUT
644 *
645 * RETURNS
646 *
647 * AUTHOR
648 *
649 * DESCRIPTION
650 *
651 * CHANGES
652 *
653 ******************************************************************************/
654 
Destroy_Warps(WarpList & warps)655 void Destroy_Warps (WarpList& warps)
656 {
657     for (WarpList::iterator iWarp = warps.begin(); iWarp != warps.end(); iWarp ++)
658         delete *iWarp;
659     warps.clear();
660 }
661 
662 
663 
664 /*****************************************************************************
665 *
666 * FUNCTION
667 *
668 * INPUT
669 *
670 * OUTPUT
671 *
672 * RETURNS
673 *
674 * AUTHOR
675 *
676 * DESCRIPTION
677 *
678 * CHANGES
679 *
680 ******************************************************************************/
681 
Copy_Warps(WarpList & rNew,const WarpList & old)682 void Copy_Warps (WarpList& rNew, const WarpList& old)
683 {
684     rNew.reserve(old.size());
685     for (WarpList::const_iterator i = old.begin(); i != old.end(); i ++)
686         rNew.push_back((*i)->Clone());
687 }
688 
689 }
690