Sine Waves

After switching to Autodesk for my complete toolchain, I’m not using Easel to generate any more g-code.

So, for those of you still interested in developing for Easel, here is my source code for the Sines application. If you’re a developer, you can use it as it for the above results. It’s only an example of the 1.0 API, so not extremely helpful, but could be useful for basic SVG coding tips.

I’m not a programmer and have never learned or used JS before, so don’t assume anything here is the best practice.

Sines_Easel.js (5.3 KB)


// Copyright 2016 Bill Bucket
// All rights reserved


// Create a circular sinusoidal depth gradient. 
// The size of the gradient shape is determined by the number of  
// rings it has and the cut width.  
// The step over determines how much of a ring overlaps with the  
// previous ring, this means peaks can be sharper and slopes steeper,  
// but the bottom of a trough can only be as narrow as the tool width.

// Define a properties array that returns array of objects representing
// the accepted properties for your application
var properties = [
  {type: 'range', id: "Tool Width [inches]", value: 0.25, min: 0.05, max: 0.5, step: 0.01},
  {type: 'range', id: "Inner Radius [inches]", value: 0.5, min: 0, max: 29, step: 0.1},
  {type: 'range', id: "Outer Radius [inches]", value: 3, min: 0.5, max: 30, step: 0.1},
  {type: 'range', id: "Scallop Height [mils]", value: 10, min: 0.1, max: 40, step: 0.1},
  {type: 'range', id: "Minimum Stepover [%]", value: 5, min: 1, max: 100, step: 1},
  {type: 'range', id: "Sin(Pi) Depth %", value: 70, min: 0, max: 100, step: 1},
  {type: 'range', id: "Sin(0) Depth %", value: 20, min: 0, max: 100, step: 1},
  {type: 'range', id: "Cycles", value: 2, min: 0.1, max: 10, step: 0.1}
];

// Define an executor function that generates a valid SVG document string,
// and passes it to the provided success callback, or invokes the failure
// callback if unable to do so
var executor = function(args, success, failure) {
  var params = args[0];
  var InnerRadius = params["Inner Radius [inches]"];
  var OuterRadius = params["Outer Radius [inches]"];
  var ToolWidth = params["Tool Width [inches]"];
  var MinStep = params["Minimum Stepover [%]"]/100;
  var ScallopHeight = params["Scallop Height [mils]"];
  var MinGradient = 255 - Math.round(params["Sin(Pi) Depth %"]/100 * 255);
  var MaxGradient = 255 - Math.round(params["Sin(0) Depth %"]/100 * 255);
  var Cycles = params["Cycles"];
  var GradRange = MaxGradient - MinGradient;

  var XCenter = OuterRadius;
  var YCenter = OuterRadius;

  // Array to hold the path strings in cutting order (first to last)
  var SvgPaths = [];
  
  if (InnerRadius > 0)
  {
    SvgPaths += [
   '<circle',
   ' cx="' + (XCenter+InnerRadius) + '"',
   ' cy="' + (YCenter) + '"',    // X and Y center location of gradient 
   ' r="' + (InnerRadius) + '"',
   ' fill="rgb(' + MaxGradient + ',' + MaxGradient + ',' + MaxGradient + ')"',          
   ' stroke="none"',
   ' stroke-width = "none"',
   ' style="stroke-linejoin:round" />' ].join("");
  }
  
  // We're tracking the radius as we move from the center plateau out to judge completeness
  var CurrentRadius = 0;
  var TravelRadius = (OuterRadius - InnerRadius);

  // Generate the appropriate number of steps with the full number of cycles
  while ((CurrentRadius+ToolWidth) < TravelRadius)
  {
   var RatioComplete = (CurrentRadius/TravelRadius);
   
   // Calculate the slope at the point in the carve
   var Slope = Math.tan(Math.sin( (RatioComplete) * Cycles * Math.PI + Math.PI/2));
   
   // The step over depends on the desired scallop height, tool diameter, and the current slope
   var StepOver =  Math.sqrt(((ToolWidth^2)/4)-((ToolWidth/2)-(ScallopHeight/1000))^2)
                 * 2*Math.cos(Slope);
                 
   StepOver = Math.min(StepOver,ToolWidth*MinStep);
   
   CurrentRadius += StepOver;
   
   // The radius for this isoline depends on the current radius ad the step over.
   var ShapeRadius = CurrentRadius + InnerRadius;
   
   // The depth depends on how far through the total steps we are and how
   // many cycles need to fit inside those steps; ride the waves
   var ShadeValue = Math.round(Math.abs(Math.sin( (RatioComplete) * Cycles * Math.PI + Math.PI/2)) * GradRange + MinGradient);
   
   // Full 360 degree arcs can't be made with the 'a' command, so these
   // arcs fall 0.0001 units short of a complete circle, close enough to
   // close without an artifact.
   // A circle object would be filled and we don't want that
   var GradientRing = [
   '<path d="M ' + (XCenter-CurrentRadius) + ',' + (YCenter),    // X and Y center location of gradient 
   ' a' + (ShapeRadius) + ',' + (ShapeRadius) + ' 0 1,1 0,0.0001 z"',
   ' fill="none"',          
   ' stroke="rgb(' + ShadeValue + ',' + ShadeValue + ',' + ShadeValue + ')"',       
   ' stroke-width = "' + ToolWidth + '"',
   ' style="stroke-linejoin:round" />' ].join("");
   
   // Add the calculated path to the array for adding to the svg later
   SvgPaths += GradientRing;
  }

  // Combine the entire svg file string
  var svg = [
    '<?xml version="1.0" standalone="no"?>',
    '<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="30in" height="30in"',
    ' viewBox="0 0 30 30">',
    SvgPaths,
    '</svg>'
  ].join("");
  
  // Return the completed string
  success(svg);
};
1 Like