POV-Ray : Newsgroups : povray.general : Spring is sprung. : Re: Spring is sprung. Server Time
4 Aug 2024 04:19:29 EDT (-0400)
  Re: Spring is sprung.  
From:
Date: 24 Sep 2003 04:05:47
Message: <3f71505b@news.povray.org>
/*

Hi Stephen!

Here is a macro for springs made of torus-segments: fast, smooth, easy to
use. Copy this whole post to POV-Ray and play with the parameters. I've
included Warp's cylinder-spring for comparison, set UseSpiralMacro to
false to see it.

Spiral with 50 SpringSegments is approximately as fast as 1200 of Warp's
cylinders, but *much* smoother: compare them at a camera angle of 3.5!

If you want to see the borders between the tori, change the 0 in one of the
plane objects to -0.02.

Ideally the spiral should touch a cylinder from inside that has a radius of
SpringMajorRadius+SpringMinorRadius. With the torus method there is a very
small (unavoidable) bulge. This can be seen by setting ShowBulgeError to
true. The value of this error is written to the debug stream.

   Sputnik

*/


// Spiral

// +SP8 +EP8 -FN +A0.1 +AM2 +R3



camera { location -z*20 look_at 0 angle 35 }
light_source { -z*10, 1 }


#declare SpringHeight = 8;
#declare SpringMajorRadius = 1;
#declare SpringMinorRadius = .1;
#declare SpringRevolutions = 10;
#declare SpringSegments = 50; // 5*SpringRevolutions is
                              // enough for #macro Spiral
#declare UseSpiralMacro = true; //
#declare ShowBulgeError = false; // true: shows the Spiral's bulge


// SPIRAL ///////////////////////////////////////////////////////////////////

#macro Spiral ( Radius1, Radius0, Rise, Turns, Segments )

  // Radius1 : major radius
  // Radius1 : minor radius
  // Rise    : height of a single turn
  // Turns   : number of turns (may be non-integer)
  // Segments: number of tori in spiral
  //           (>= 2*Turns; usually 5*Turns ... 10*Turns is enough)

  // some calculations ...
  #local Ang= Turns*360/Segments;
  #local Ri = Rise/2 * Turns/Segments;
  #local Sin= sin(radians(Ang/2));
  #local A  = Radius1*Sin;
  #local B  = sqrt(Radius1*Radius1-A*A);
  #local C  = A*A/B;
  #local DD = Ri*Ri+A*A;
  #local E  = DD/C;
  #local W  = degrees(atan2(C,sqrt(DD)));
  #local R  = sqrt(E*(E+C));

  // single torus-segment
  #declare T =
    intersection {
      torus { R, Radius0 }
      plane { -x, 0 rotate  W*y }
      plane {  x, 0 rotate -W*y }
      bounded_by { box {
        1.001*<-(R+Radius0)*Sin, -Radius0, -(R+Radius0)>,
        1.001*< (R+Radius0)*Sin,  Radius0, -(R-Radius0)*(1-Sin*Sin)>
        } }
      rotate -degrees(atan2(Ri,A))*z
      translate <0, Ri, E-B>
      rotate Ang/2*y
      }

  // the torus-segments have a small bulge
  #local Err = R-Radius1-E+B;
  #debug concat (
    "\nMaximum radius error in 'Spiral' = ", str(Err,0,5),
    " = ", str(Err/Radius1*100,0,3), " %\n"
    )

  // stack the segments
  union {
    #local N = 0;
    #while (N<Segments)
      object { T rotate N*Ang*y translate N*2*Ri*y }
      #local N = N+1;
      #end//while
    // no "}" to allow modifiers

  #end//macro Spiral


/////////////////////////////////////////////////////////////////////////////

#if (UseSpiralMacro)

  // spring consisting of torus-segments
  #declare Spring =
    Spiral (
      SpringMajorRadius,
      SpringMinorRadius,
      SpringHeight/SpringRevolutions,
      SpringRevolutions,
      SpringSegments // 5*SpringRevolutions usually is enough
      ) /* { */ rotate -90*y /* same orientation as Warp's spring */ }

  #if (ShowBulgeError)
      difference {
        object { Spring }
        cylinder { 0, SpringHeight*y, SpringMajorRadius+SpringMinorRadius }
        pigment { rgb 1 } finish { specular .5 }
        translate -4*y
        }
      #else
        object { Spring
          translate -4*y
          pigment { rgb 1 } finish { specular .5 }
          }
    #end//if ShowBulgeError

  #else

    // spring consisting of cylinders as suggested by Warp
    union
    {
      #declare Ind = 0;
      #while(Ind <= SpringSegments)
        #declare Pos2 =
          vrotate(<SpringMajorRadius, SpringHeight*Ind/SpringSegments, 0>,
                  y*360*SpringRevolutions*Ind/SpringSegments);
        #if(Ind > 0)
          cylinder { Pos1, Pos2, SpringMinorRadius }
          sphere { Pos2, SpringMinorRadius }
        #end
        #declare Pos1 = Pos2;
        #declare Ind = Ind+1;
      #end

      pigment { rgb 1 } finish { specular .5 }
      translate -y*4
    }

  #end//if UseSpiralMacro


box { <-2,-4,-2><2,-4.1,2> pigment { rgb <.8,.4,.2> } }


// END //////////////////////////////////////////////////////////////////////


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.