POV-Ray : Newsgroups : povray.text.scene-files : "Twisted Lathe" Source Code : "Twisted Lathe" Source Code Server Time
28 Jul 2024 14:32:21 EDT (-0400)
  "Twisted Lathe" Source Code  
From: Tor Olav Kristensen
Date: 12 Jun 2000 10:26:48
Message: <3944F334.E80285DD@hotmail.com>
Below is the source code for an image I posted 4. June to the
povray.binaries.images news group.

The last macros may be a little non intuitive to use and I'm
working on them to make them easier to use.

Note that many of the macros below are "work in progress" and 
therefore I haven't yet optimized them for speed or compactness.

Tor Olav


// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7
// Copyright 2000 by Tor Olav Kristensen
// mailto:tor### [at] hotmailcom
// http://www.crosswinds.net/~tok/tokrays.html
// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7

#version 3.1;
#include "colors.inc"

global_settings { ambient_light 1.2 }

// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7
// First some "standard" geometry macros

// Returns projection of vector in direction of other vector
#macro vproject(UU, VV)

  (VV*vdot(UU, VV)/vdot(VV, VV))

#end // macro vproject


// Point To Plane
// Returns projection of point to plane
#macro pt2pl(pPoint, pPlane, vPlane)

  (pPoint - vproject(pPoint - pPlane, vPlane))

#end // macro pt2pl


// Point To Line
// Returns projection of point to line
#macro pt2ln(pPoint, pLine, vLine) 

  (pLine + vproject(pPoint - pLine, vLine))

#end // macro pt2ln


// Line To Plane
// Returns intersection of line and plane
#macro ln2pl(pLine, vLine, pPlane, vPlane)

  (pLine + vLine*vdot(pPlane - pLine, vPlane)/vdot(vLine, vPlane))

#end // macro ln2pl


// Plane To Plane
// Calculates line in intersection of two planes
#macro pl2pl(pPlane1, vPlane1, pPlane2, vPlane2, pLine, vLine)

  #declare vLine = vcross(vPlane1, vPlane2);
  #local vInPlane2 = vcross(vLine, vPlane2);
  #declare pLine = ln2pl(pPlane2, vInPlane2, pPlane1, vPlane1);

#end // macro pl2pl


// Returns object tilted in direction of vector
#macro Tilt(Thing, Vector)

  #local xAngle = (Vector.z < 0 ? -1 : 1)*
                  degrees(acos(vnormalize((x + z)*Vector).x));
  #local yAngle = degrees(acos(vnormalize(Vector).y));

  object {
    Thing
    rotate  xAngle*y
    rotate -yAngle*z
    rotate -xAngle*y
  }

#end // macro Tilt

// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7
// Some macros to generate lathes from arrays of 2D-points

#macro InsertPoints(PointArray)

  #local NrOfPoints = dimension_size(PointArray, 1);
  #local PtCnt = 0;

  #while (PtCnt < NrOfPoints)
    PointArray[PtCnt],
    #local PtCnt = PtCnt + 1;
  #end // while

#end // macro InsertPoints 


#macro LinearLathe(PointArray)

  lathe {
    linear_spline
    dimension_size(PointArray, 1) + 1,
    InsertPoints(PointArray)
    PointArray[0]
  }

#end // macro LinearLathe


#macro QuadraticLathe(PointArray)

  lathe {
    quadratic_spline
    dimension_size(PointArray, 1) + 2,
    InsertPoints(PointArray)
    PointArray[0],
    PointArray[1]
  }

#end // macro QuadraticLathe


#macro CubicLathe(PointArray)

  lathe {
    cubic_spline
    dimension_size(PointArray, 1) + 3,
    InsertPoints(PointArray)
    PointArray[0],
    PointArray[1],
    PointArray[2]
  }

#end // macro CubicLathe 

// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7
// A macro to generate array of 2D-points that can be used 
// to make torus-like lathes where the minor radius varies
// according to a "wave function", which is declared later.

#macro CalcLatheTorus(PointArray, Angle, 
                      MajorRadius, MinorRadius, ModRadius)

  #local NrOfPts = dimension_size(PointArray, 1);
  #local dPhi = 2*pi/NrOfPts;
  #local PtCnt = 0;
  #while (PtCnt < NrOfPts)
    #local Phi = PtCnt*dPhi;
    #local WaveRadius =  ModRadius*WaveFunction(Phi);
    #declare PointArray[PtCnt] = MajorRadius*u + 
                                 (MinorRadius + WaveRadius)*
                                 <cos(Angle), sin(Angle)>;
    #local PtCnt = PtCnt + 1;
    #local Angle = Angle + dPhi;
  #end

#end // macro CalcLatheTorus 

// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7
// And then the macros that generates all the 
// different lathe segments and assembles them.

#macro v2Dir(v2D, vBasis1, vBasis2)

  (v2D.u*vnormalize(vBasis1) + v2D.v*vnormalize(vBasis2))

#end // macro v2Dir


#macro New3DCoord(LatheArray, PointArray, pRef, vSd, vFw)

  #local NrOfPts = dimension_size(PointArray, 1);

  #local Cnt = 0;
  #while (Cnt < NrOfPts)
    #declare PointArray[Cnt] = pRef + v2Dir(LatheArray[Cnt], vSd, vFw);
    #local Cnt = Cnt + 1;
  #end // while

#end // macro NewCoord


#macro Lathe2DCoord(pSwp, pLine, vLine)
  
  #local pHit = pt2ln(pSwp, pLine, vLine);
  #local vForw = pHit - pLine;
  #local vSide = pSwp - pHit;
  #local Sign = (vdot(vForw, vLine) < 0 ? -1 : 1);

  <vlength(vSide), Sign*vlength(vForw)>

#end // macro Lathe2DCoord


#macro ShiftLathe(LatheType, PointArray, pRef, 
                  pPlane1, vPlane1, 
                  pPlane2, vPlane2)

  #local pLine = <0, 0, 0>;
  #local vLine = <0, 0, 0>;
  pl2pl(pPlane1, vPlane1, pPlane2, vPlane2, pLine, vLine)
  #declare pRef = pt2ln(pRef, pLine, vLine);
  #local vFw = vnormalize(vLine);
  #local vSd = vnormalize(vcross(vPlane2, vFw));
  #local NrOfPts = dimension_size(PointArray, 1);
  #local LatheArray = array[NrOfPts]
  #local Cnt = 0;
  #while (Cnt < NrOfPts)
    #local LatheArray[Cnt] = Lathe2DCoord(PointArray[Cnt], pRef, vFw);
    #declare PointArray[Cnt] = pRef + v2Dir(LatheArray[Cnt], vSd, vFw);
    #local Cnt = Cnt + 1;
  #end // while
  New3DCoord(LatheArray, PointArray, pRef, vSd, vFw)

  #switch (LatheType)
    #case (1)
      #local Lathe = LinearLathe(LatheArray)
      #break
    #case (2)
      #local Lathe = QuadraticLathe(LatheArray)
      #break
    #case (3)
      #local Lathe = CubicLathe(LatheArray)
      #break
    #else
      #debug "Macro ShiftLathe: Wrong lathe type"
  #end

  intersection {
    Tilt(Lathe, vFw)
    plane { -vPlane1, 0 } // Look here to learn how to select "signs"
    plane {  vPlane2, 0 } // for the plane normals in the plane array.
    translate pRef
  }

#end // macro ShiftLathe


#macro LatheSway(LatheArray, pRef, PlaneArray, LatheType)

  #local PointArray = array [dimension_size(LatheArray, 1)]
  #local vFw = vnormalize(vcross(PlArray[0][1], PlArray[1][1]));
  #local vSd = vnormalize(vcross(vFw, PlArray[0][1]));
  New3DCoord(LatheArray, PointArray, pRef, vSd, vFw)

  merge {
    #declare PlCnt = 1;
    #while (PlCnt < dimension_size(PlArray, 1))
      ShiftLathe(LatheType, PointArray, pRef, 
                 PlArray[PlCnt - 1][0], PlArray[PlCnt - 1][1],
                 PlArray[PlCnt - 0][0], PlArray[PlCnt - 0][1])
      #declare PlCnt = PlCnt + 1;
    #end // while
  }
  
#end // macro LatheSway

// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7
// Now have fun.
 
#macro WaveFunction(Phi)

  (2/3*cos(4*Phi) - 1/3*sin(6*Phi - pi/2))

#end // macro WaveFunction


#declare LathePoints = array[96]
CalcLatheTorus(LathePoints, pi/2, 12, 2, 8)


/*
#macro WaveFunction(Phi)

  cos(6*Phi)

#end // macro WaveFunction


#declare LathePoints = array[72]
CalcLatheTorus(LathePoints, pi/12, 10, 6, 1)
*/


// The planes below:
// plane { PlArray[n][1], 0 translate PlArray[n][0] }
//
// Note: Changing the "sign" of each normal vector
//       gives different CSG-results
#declare PlArray =
array[6][2] {
  { < 20,  0,   0>, <-2,  1,  0> },
  { <  0,  0, -10>, < 0,  1,  1> },
  { <-20,  0,   0>, <-2, -1,  0> },
  { <  0, 20,   0>, < 0,  1,  0> },
  { <  0, 24,   0>, < 0,  1, -3> },
  { <  0, 40,   0>, < 0,  1,  0> }
}


// Just a quick and dirty way to select a
// first reference point in the first plane
#declare pFirstRef = pt2pl(<2, 2, 2>, PlArray[0][0], PlArray[0][1]);
// Could also have written
//#declare pFirstRef = <17.2, -5.6, 2.0>;


#declare Sway = LatheSway(LathePoints, pFirstRef, PlArray, 3)


// Then use symmetry to cheat a little bit
union {
  object {
    Sway
    translate -40*y
  }
  object {
    Sway
    translate -40*y
    scale <1, -1, 1>
  }
  rotate 90*x
  pigment { color Red }
}


// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7
/*
// A much simpler lathe shape in the XZ-plane
// Use other camera position to view

#macro WaveFunction(Phi)

  0

#end // macro WaveFunction


#declare LathePoints = array[5]
CalcLatheTorus(LathePoints, pi/10, 24, 6, 0)


// Example of manually entered array of 2D-points for lathe:
//#declare LathePoints = 
//array[4] {
//  <24, 0> + 4*<1, 0>,
//  <24, 0> + 4*<0, 1>,
//  <24, 0> - 4*<1, 0>,
//  <24, 0> - 4*<0, 1>
//}


#declare PlArray =
array[9][2] {
  {  20*x,  x },
  {  20*z,  z },
  {  20*x, -x },
  {  20*z, -z },
  { -20*x, -x },
  { -20*z, -z },
  { -20*x,  x },
  { -20*z,  z },
  {  20*x,  x }
}


#declare pFirstRef = 18*(x + z);

#declare SimpleSway = LatheSway(LathePoints, pFirstRef, PlArray, 2)

object {
  SimpleSway
//  rotate 45*y
  translate 20*y
  pigment { color Cyan }
}
*/
// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7

sky_sphere { pigment { color Grey } }

#declare AreaLight =
light_source { 
  100*y, 
  color White
  area_light 10*x, 10*z, 3, 3
  jitter
}

Tilt(AreaLight, <-1, sqrt(2), 1>)
Tilt(AreaLight, -y)

#declare CameraPos = 60*<-2, 0.4, 0.6>;
//#declare CameraPos = 60*<-2, 1, 0.6>;
//#declare CameraPos = 70*<0, 2, -1/100>;

//light_source { CameraPos color 0.7*White  } 

camera {
  location CameraPos
  look_at <0, -10, 0>
}

// ===== 1 ======= 2 ======= 3 ======= 4 ======= 5 ======= 6 ======= 7


Post a reply to this message

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