Creating a Waveform Geometry

The objective of this tutorial is to refresh your understanding of a few fundamental concepts in design computation, namely general signal processing, linear/non-linear transformation, density-distribution functions, generating geometry though iterative constructs and high-level overview of data types and containers thereof. This tutorial is in anticipation of moving from computation geometry into machine motion planning from first principles.


  1. We will generate grid of point at regular intervals. This is captured through a nested loop construct which we iterate externally per column and internally per row.
  2. We will transform or map the integer numbers provided by the control variables onto the unit line segment of real numbers. This is to review the notion of normalization and linear interpolation. It is to remind you that multiplication and division of numbers conveys the geometric meaning of scaling.
  3. We proceed with applying a non-linear filter to the regular interval of the unit line to modify the density-distribution of sequence (or signal). Any function that passes through the origin (0,0) and the unit point (1,1) will suffice. In the example we use a quadratic monomial and the square root.
  4. We compute a height-field function which translates horizontal coordinates to vertical elevation. This takes the form of an implicit bi-variate scalar function f( x, y ) = z. The particular form of using the product of sine and cosine is used to create an undulating surface.
  5. The transformation applied by the products of trigonometric functions is also non-linear. However, the interior transformation of abstract units to angles is linear. We use 2pi scaled by the number of turns around the circle (the period) and we translate the signal using and phase parameter.
  6. We have thus established that in linear space multiplication/division represents scaling and addition/subtraction geometrically represents translation.
  7. The point coordinates are mapped onto physical dimensions by the introduction of real sizes, namely the scaling factors per direction.
  8. The second aspect presented here is how to collect the generate information, namely the points themselves into lists and configure the sequence such that it produces a serpentine continuous polyline.
  9. The point to note is that for each scan of an entire row of points on the grid, the points are collected in a list named row. At the end of each iteration we determine whether or not to reverse the order of points into the row collection before transferring them into the master point collection.
  10. The logic behind the selective reversal is based on the final transformation covered today which has to do with discrete signals. Namely we use integer division or modular arithmetic to determine if the order of a particular row is even or odd. The remainder of the integer division, also known as the module, will be always zero for even numbers and one for odd numbers.


private void RunScript( int nx, int ny, 
  double PeriodX, double PeriodY, double PhaseX, double PhaseY, 
  double ScaleZ, double ScaleX, double ScaleY, 
  ref object Geometry, ref object AnnoTxts, ref object AnnoPnts )
  //-- SOP IN
  geometry = new List<object>();
  annotxts = new List<string>();
  annopnts = new List<Point3d>();

  //-- Magic goes here
  var points = new List<Point3d>();
  for( var iy = 0; iy < ny; iy++ )
     var row = new List<Point3d>( );
     for( var ix = 0; ix < nx; ix++ )
       var tx = (double) ix / (double) ( nx - 1 );
       var ty = (double) iy / (double) ( ny - 1 );

       var sx = tx * tx;
       var sy = Math.Sqrt( ty );

       var tz =
         Math.Cos( sx * Math.PI * 2 * PeriodX + PhaseX ) *
         Math.Sin( sy * Math.PI * 2 * PeriodY + PhaseY );

       var pt = new Point3d(
         tx * ScaleX,
         ty * ScaleY,
         tz * ScaleZ + ScaleZ );

    if(( iy % 2 ) == 0 ) 
       row.Reverse( );
    points.AddRange( row );

  geometry.Add( new Polyline( points ) );

  //-- SOP OUT
  Geometry = geometry;
  AnnoPnts = annopnts;
  AnnoTxts = annotxts;

// <Custom additional code> 

public List<object> geometry;
public List<string> annotxts;
public List<Point3d> annopnts;

public void Log(Point3d point, string message)
// </Custom additional code>