|
|
/*
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
|
|