parametric3D.frink

View or download parametric3D.frink in plain text format


/** This program extrudes 3-D models along a parametric curve.  It is quite
    smart and creates its own adaptive step size to move along the parameter
    with a minimum of steps but without gaps in the tool's position.

    TODO:  Add a two-variable parametric equation which is trickier.  Ideally,
    the function passed in should be differentiable by Frink which would allow
    intelligent step sizes to be calculated directly.
*/


/** This calculates the tool path to move a tool along a parametric curve
    specified by a function f that takes two arguments:

     f[t, data]
      where t is a value that increases from t0 to t1 and data is  an
      arbitrary expression that can be used to pass additional data to the
      function.  The function should return an array of [x, y, z] values with
      dimensions of length.

     res:  The resolution of the model with dimensions of inverse length, e.g.,
        254/inch

     This function is smart in that it adaptively adjusts the step used to move
     the parameter t with a minimum of steps but without gaps in the tool's
     position.

     This returns a frink.graphics.Point3DIntList which specifies 3-D integer
     coordinates where the tool should pass through.  The tool's path can be
     instantiated into a 3-D model using VoxelArray.paintAlongPath 
*/

calculatePath[f, data, t0, t1, res] :=
{
   points = newJava["frink.graphics.Point3DIntList", []]
   tstep = (t1-t0)/1000.    // This timestep will be auto-adjusted.
   t = t0

   [x, y, z] = f[t, data]

   //   println["$x, $y, $z"]
   ix = round[x res]
   iy = round[y res]
   iz = round[z res]
   points.addPoint[ix, iy, iz]

   lx = x
   ly = y
   lz = z
   
   while t <= t1
   {
      do
      {
         tryagain = false
         [x, y, z] = f[t+tstep, data]

         ix = round[x res]
         iy = round[y res]
         iz = round[z res]

         dx = abs[x - lx] res
         dy = abs[y - ly] res
         dz = abs[z - lz] res

         idx = round[dx]
         idy = round[dy]
         idz = round[dz]

         // Check to see if the voxel didn't move or if it moved by more than
         // 1 pixel on any axis.  If so, adjust the step mathematically.
         if ((idx== 0) and (idy == 0) and (idz==0)) or (abs[idx]>1) or (abs[idy]>1) or (abs[idz]>1)
         {
            d = sqrt[dx^2 + dy^2 + dz^2]
            //d = max[[dx, dy, dz]]
            if d > .98 and d < 1.02    // Prevent too-small adjustments
               d = d^2
            tstep = tstep / d
            println["Adjusting tstep to $tstep"]
            tryagain = true
         } else
         {
//            println["$ix $iy $iz"]
            points.addPoint[ix, iy, iz]
         }
      } while tryagain

      lx = x
      ly = y
      lz = z
      t = t + tstep
   }

   // Make sure we contain the exact last point.
   [x, y, z] = f[t1, data]
   ix = round[x res]
   iy = round[y res]
   iz = round[z res]
   points.addPoint[ix, iy, iz]

   return points
}

/** Sample parametric function to draw a helix.  The "data" parameter is
    [radius, pitch, angle0]  where angle0 indicates the "start"
    of the curve.
*/

helix[t, data] :=
{
   [radius, pitch, angle0] = data
   //   if t0 == undef
   //      t0 = 0
   tt = t + angle0
   x = radius cos[tt]
   y = radius sin[tt]
   z = (t / (2 pi)) pitch

   return [x, y, z]
}

// Sample parametric function to draw a Moebius strip.  See
// https://mathworld.wolfram.com/MoebiusStrip.html
// s should vary from -w to w where w is the half-width
// T should vary from 0 to 2 pi
MobiusStrip[t, data] :=
{
   [R, s] = data
   x = (R + s cos[1/2 t]) cos[t]
   y = (R + s cos[1/2 t]) sin[t]
   z = s sin[1/2 t]

   return [x,y,z]
}


View or download parametric3D.frink in plain text format


This is a program written in the programming language Frink.
For more information, view the Frink Documentation or see More Sample Frink Programs.

Alan Eliasen was born 19030 days, 12 hours, 20 minutes ago.